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

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;

use sputnikvm::{Gas, Address};
use bigint::{U256, M256, read_hex};
use sputnikvm::vm::{BlockHeader, Context, SeqTransactionVM, Transaction, VM, Patch, AccountCommitment, Account, FRONTIER_PATCH};
use sputnikvm::vm::errors::RequireError;
use gethrpc::{regression, GethRPCClient, RPCCall, RPCBlock, RPCTransaction};

fn upfront_cost(data: &str) -> Gas {
    let mut cost = Gas::from(21000u64);
    let data = read_hex(data).unwrap();
    for v in data {
        if v == 0 {
            cost = cost + Gas::from(4u64);
        } else {
            cost = cost + Gas::from(68u64);
        }
    }
    return cost;
}

fn from_rpc_block(block: &RPCBlock) -> BlockHeader {
    BlockHeader {
        coinbase: Address::from_str(&block.miner).unwrap(),
        timestamp: M256::from_str(&block.timestamp).unwrap(),
        number: M256::from_str(&block.number).unwrap(),
        difficulty: M256::from_str(&block.difficulty).unwrap(),
        gas_limit: Gas::from_str(&block.gasLimit).unwrap(),
    }
}

fn from_rpc_transaction(transaction: &RPCTransaction) -> Transaction {
    Transaction::MessageCall {
        caller: Address::from_str(&transaction.from).unwrap(),
        address: 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(),
        data: read_hex(&transaction.input).unwrap(),
    }
}

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`.")
    ).get_matches();

    let address = matches.value_of("RPC").unwrap();
    let mut client = GethRPCClient::new(address);

    println!("net version: {}", client.net_version());

    let block = client.get_block_by_number(format!("0x{:x}", 49439).as_str());
    println!("block {}, transaction count: {}", block.number, block.transactions.len());
    let last_block_number = format!("0x{:x}", M256::from_str(&block.number).unwrap() - M256::from(1u64));

    let block_header = from_rpc_block(&block);

    for transaction_hash in block.transactions {
        println!("\nworking on transaction {}", transaction_hash);
        let transaction = client.get_transaction_by_hash(&transaction_hash);
        println!("transaction: {:?}", transaction);
        let receipt = client.get_transaction_receipt(&transaction_hash);
        println!("receipt: {:?}", receipt);
        if transaction.to.is_empty() {
            unimplemented!();
        }

        let transaction = from_rpc_transaction(&transaction);

        let mut vm = SeqTransactionVM::new(transaction, block_header.clone(), &FRONTIER_PATCH);
        loop {
            match vm.fire() {
                Ok(()) => {
                    println!("VM exited successfully, checking results ...");
                    break;
                },
                Err(RequireError::Account(address)) => {
                    println!("Feeding VM account at 0x{:x} ...", address);
                    let nonce = M256::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();
                    vm.commit_account(AccountCommitment::Full {
                        nonce: nonce,
                        address: address,
                        balance: balance,
                        code: code,
                    });
                },
                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,
                    });
                },
                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,
                    });
                }
                Err(err) => {
                    println!("Unhandled require: {:?}", err);
                    unimplemented!()
                },
            }
        }

        println!("\ntests after the vm has run:");
        println!("1. return status: {:?}", vm.status());
        println!("2. test gasUsed == {}, actual VM result: 0x{:x}", receipt.gasUsed, vm.used_gas());
        println!("3. logs and order is {:?}, actual VM result: {:?}", receipt.logs, vm.logs());

        println!("\nwhen the block is finished, test:");
        println!("1. balances of all used accounts.");
        println!("2. storage values touched.");
        for account in vm.accounts() {
            match account {
                &Account::Full {
                    address,
                    balance,
                    ref changing_storage,
                    ..
                } => {
                    let expected_balance = client.get_balance(&format!("0x{:x}", address),
                                                              &block.number);
                    println!("account 0x{:x}, balance: 0x{:x} == {}", address,
                             balance, expected_balance);
                    let changing_storage: HashMap<M256, 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),
                                                                   &block.number);
                        println!("account 0x{:x}, storage 0x{:x}: 0x{:x} == {}", address,
                                 key, value, expected_value);
                    }
                },
                _ => unimplemented!(),
            }
        }
    }
}
<commit_msg>Problem: unused fn upfront cost<commit_after>#[macro_use]
extern crate clap;
extern crate sputnikvm;
extern crate bigint;
extern crate serde_json;
extern crate gethrpc;

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;

use sputnikvm::{Gas, Address};
use bigint::{U256, M256, read_hex};
use sputnikvm::vm::{BlockHeader, Context, SeqTransactionVM, Transaction, VM, Patch, AccountCommitment, Account, FRONTIER_PATCH};
use sputnikvm::vm::errors::RequireError;
use gethrpc::{regression, GethRPCClient, RPCCall, RPCBlock, RPCTransaction};

fn from_rpc_block(block: &RPCBlock) -> BlockHeader {
    BlockHeader {
        coinbase: Address::from_str(&block.miner).unwrap(),
        timestamp: M256::from_str(&block.timestamp).unwrap(),
        number: M256::from_str(&block.number).unwrap(),
        difficulty: M256::from_str(&block.difficulty).unwrap(),
        gas_limit: Gas::from_str(&block.gasLimit).unwrap(),
    }
}

fn from_rpc_transaction(transaction: &RPCTransaction) -> Transaction {
    Transaction::MessageCall {
        caller: Address::from_str(&transaction.from).unwrap(),
        address: 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(),
        data: read_hex(&transaction.input).unwrap(),
    }
}

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`.")
    ).get_matches();

    let address = matches.value_of("RPC").unwrap();
    let mut client = GethRPCClient::new(address);

    println!("net version: {}", client.net_version());

    let block = client.get_block_by_number(format!("0x{:x}", 49439).as_str());
    println!("block {}, transaction count: {}", block.number, block.transactions.len());
    let last_block_number = format!("0x{:x}", M256::from_str(&block.number).unwrap() - M256::from(1u64));

    let block_header = from_rpc_block(&block);

    for transaction_hash in block.transactions {
        println!("\nworking on transaction {}", transaction_hash);
        let transaction = client.get_transaction_by_hash(&transaction_hash);
        println!("transaction: {:?}", transaction);
        let receipt = client.get_transaction_receipt(&transaction_hash);
        println!("receipt: {:?}", receipt);
        if transaction.to.is_empty() {
            unimplemented!();
        }

        let transaction = from_rpc_transaction(&transaction);

        let mut vm = SeqTransactionVM::new(transaction, block_header.clone(), &FRONTIER_PATCH);
        loop {
            match vm.fire() {
                Ok(()) => {
                    println!("VM exited successfully, checking results ...");
                    break;
                },
                Err(RequireError::Account(address)) => {
                    println!("Feeding VM account at 0x{:x} ...", address);
                    let nonce = M256::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();
                    vm.commit_account(AccountCommitment::Full {
                        nonce: nonce,
                        address: address,
                        balance: balance,
                        code: code,
                    });
                },
                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,
                    });
                },
                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,
                    });
                }
                Err(err) => {
                    println!("Unhandled require: {:?}", err);
                    unimplemented!()
                },
            }
        }

        println!("\ntests after the vm has run:");
        println!("1. return status: {:?}", vm.status());
        println!("2. test gasUsed == {}, actual VM result: 0x{:x}", receipt.gasUsed, vm.used_gas());
        println!("3. logs and order is {:?}, actual VM result: {:?}", receipt.logs, vm.logs());

        println!("\nwhen the block is finished, test:");
        println!("1. balances of all used accounts.");
        println!("2. storage values touched.");
        for account in vm.accounts() {
            match account {
                &Account::Full {
                    address,
                    balance,
                    ref changing_storage,
                    ..
                } => {
                    let expected_balance = client.get_balance(&format!("0x{:x}", address),
                                                              &block.number);
                    println!("account 0x{:x}, balance: 0x{:x} == {}", address,
                             balance, expected_balance);
                    let changing_storage: HashMap<M256, 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),
                                                                   &block.number);
                        println!("account 0x{:x}, storage 0x{:x}: 0x{:x} == {}", address,
                                 key, value, expected_value);
                    }
                },
                _ => unimplemented!(),
            }
        }
    }
}
<|endoftext|>


<commit_before>include!(concat!(env!("OUT_DIR"), "/compiled-data.rs"));

mod utils;

use crate::utils::set_panic_hook;
#[macro_use]
extern crate lazy_static;
use serde::Serialize;
use std::collections::HashMap;
use std::convert::TryFrom;
use wasm_bindgen::prelude::*;

// When the `wee_alloc` feature is enabled, use `wee_alloc` as the global
// allocator.
#[cfg(feature = "wee_alloc")]
#[global_allocator]
static ALLOC: wee_alloc::WeeAlloc = wee_alloc::WeeAlloc::INIT;

#[wasm_bindgen]
extern "C" {
    fn alert(s: &str);
}

#[wasm_bindgen]
pub fn greet() {
    alert("Hello, unicode-rustwasm!");
}

#[wasm_bindgen]
pub fn init() {
    set_panic_hook();
}

#[wasm_bindgen]
pub fn next_codepoint(codepoint: u32) -> u32 {
    if codepoint != 0x10FFFF {
        codepoint + 1
    } else {
        0
    }
}

#[wasm_bindgen]
pub fn previous_codepoint(codepoint: u32) -> u32 {
    if codepoint != 0 {
        codepoint - 1
    } else {
        0x10FFFF
    }
}

#[derive(Copy, Clone, Serialize)]
struct IdeographicVariationSequence {
    base_codepoint: u32,      // base codepoint
    variation_selector: u32,  // variation selector
    collection: &'static str, // collection
    item: &'static str,       // item, i.e. index into collection
}

#[wasm_bindgen]
pub fn variation_sequences_for_codepoint(codepoint: u32) -> String {
    let mut result = Vec::<IdeographicVariationSequence>::new();
    for ivd in IVD_SEQUENCES.iter() {
        if ivd.base_codepoint == codepoint {
            result.push(ivd.clone());
        }
    }
    serde_json::to_string(&result).unwrap()
}

#[wasm_bindgen]
pub fn u8toc(utf8_bytes: Vec<u8>) -> Option<Vec<u32>> {
    match std::str::from_utf8(utf8_bytes.as_slice()) {
        Err(_) => None,
        Ok(s) => Some(s.chars().map(|ch| u32::from(ch)).collect()),
    }
}

#[wasm_bindgen]
pub fn ctou8(codepoints: Vec<u32>) -> Option<Vec<u8>> {
    Some(ctos(codepoints)?.bytes().collect())
}

#[wasm_bindgen]
pub fn ctos(codepoints: Vec<u32>) -> Option<String> {
    let maybe_a_string = codepoints
        .iter()
        .map(|num| char::try_from(*num))
        .collect::<Result<String, _>>();
    match maybe_a_string {
        Err(_) => None,
        Ok(s) => Some(s),
    }
}

#[wasm_bindgen]
pub fn stoc(str: &str) -> Vec<u32> {
    str.chars().map(|ch| ch as u32).collect()
}

#[derive(Clone, Serialize)]
pub struct EncodingResult {
    pub success: bool,
    pub encoded_code_units: Option<Vec<u32>>,
    pub first_invalid_codepoint: Option<u32>,
}

// map codepoints -> code units
pub type EncodingTable = HashMap<u32, u32>;

// lazy_static! {
//     static ref ENCODING_TABLES: HashMap<&'static str, EncodingTable> = {
//         let mut encoding_table = HashMap::new();
//         encoding_table.insert("ASCII", [(0, 0), (1, 1)]);
//         encoding_table
//     };
// }

fn encode_str_internal(encoding_name: &str, codepoints: Vec<u32>) -> EncodingResult {
    if encoding_name == "Unicode UTF-8" {
        return match ctou8(codepoints) {
            Some(str) => EncodingResult {
                success: true,
                encoded_code_units: Some(str.iter().map(|u| *u as u32).collect()),
                first_invalid_codepoint: None,
            },
            None => EncodingResult {
                success: false,
                encoded_code_units: None,
                first_invalid_codepoint: None,
            },
        };
    }
    let code_units: Result<Vec<u32>, u32> = if encoding_name == "Unicode UTF-32 (32-bit code units)"
    {
        codepoints
            .iter()
            .map(|&cp| {
                if (cp >= 0xd800 && cp <= 0xdfff) || cp > 0x10ffff {
                    Err(cp)
                } else {
                    Ok(cp)
                }
            })
            .collect()
    } else {
        let encoding = match ENCODING_TABLES.get(encoding_name) {
            Some(encoding) => encoding,
            None => {
                return EncodingResult {
                    success: false,
                    encoded_code_units: None,
                    first_invalid_codepoint: None,
                }
            }
        };
        codepoints
            .iter()
            .map(|&codepoint| {
                encoding
                    .get(&codepoint)
                    .ok_or(codepoint)
                    .map(|code_unit| *code_unit)
            })
            .collect()
    };
    match code_units {
        Ok(code_units) => EncodingResult {
            success: true,
            encoded_code_units: Some(
                code_units
                    .iter()
                    .copied()
                    .flat_map(|cu| {
                        if cu <= 0xff {
                            vec![cu]
                        } else {
                            vec![cu >> 8, cu & 0xff]
                        }
                    })
                    .collect(),
            ),
            first_invalid_codepoint: None,
        },
        Err(codepoint) => EncodingResult {
            success: false,
            encoded_code_units: None,
            first_invalid_codepoint: Some(codepoint),
        },
    }
}

#[wasm_bindgen]
pub fn encode_str(encoding_name: &str, codepoints: Vec<u32>) -> String {
    let result = encode_str_internal(encoding_name, codepoints);
    serde_json::to_string(&result).unwrap()
}

fn lookup_code_unit(table: &EncodingTable, code_unit: u32) -> Option<u32> {
    for (&k, &v) in table {
        if v == code_unit {
            return Some(k);
        }
    }
    None
}

#[wasm_bindgen]
pub fn decode_str(encoding_name: &str, code_units: Vec<u32>) -> Option<Vec<u32>> {
    if encoding_name == "Unicode UTF-8" {
        return u8toc(
            code_units
                .iter()
                .map(|u| if *u <= 0xff { Some(*u as u8) } else { None })
                .collect::<Option<Vec<u8>>>()?,
        );
    }
    let table = ENCODING_TABLES.get(encoding_name)?;
    let mut res: Vec<u32> = vec![];
    let mut try_combined = false;
    for (i, cu) in code_units.iter().enumerate() {
        if try_combined {
            match lookup_code_unit(table, code_units[i - 1] << 8 | cu) {
                Some(cp) => {
                    res.push(cp);
                    try_combined = false;
                }
                None => return None,
            }
        } else {
            match lookup_code_unit(table, *cu) {
                Some(cp) => res.push(cp),
                None => try_combined = true,
            }
        }
    }
    return Some(res);
}

#[wasm_bindgen]
pub fn long_category_name_for_short_name(short_name: &str) -> Option<String> {
    use std::str::FromStr;
    use unicode_rs::general_category::GeneralCategory;

    Some(
        GeneralCategory::from_str(short_name)
            .ok()?
            .long_name()
            .to_string(),
    )
}

#[wasm_bindgen]
pub fn basic_type_for_codepoint(
    short_general_category_name: &str,
    codepoint: u32,
) -> Option<String> {
    use std::str::FromStr;
    use unicode_rs::general_category::GeneralCategory;

    Some(
        GeneralCategory::from_str(short_general_category_name)
            .ok()?
            .codepoint_type(codepoint)
            .to_string(),
    )
}
<commit_msg>Surrogates can no longer be utf-32 encoded<commit_after>include!(concat!(env!("OUT_DIR"), "/compiled-data.rs"));

mod utils;

use crate::utils::set_panic_hook;
#[macro_use]
extern crate lazy_static;
use serde::Serialize;
use std::collections::HashMap;
use std::convert::TryFrom;
use wasm_bindgen::prelude::*;

// When the `wee_alloc` feature is enabled, use `wee_alloc` as the global
// allocator.
#[cfg(feature = "wee_alloc")]
#[global_allocator]
static ALLOC: wee_alloc::WeeAlloc = wee_alloc::WeeAlloc::INIT;

#[wasm_bindgen]
extern "C" {
    fn alert(s: &str);
}

#[wasm_bindgen]
pub fn greet() {
    alert("Hello, unicode-rustwasm!");
}

#[wasm_bindgen]
pub fn init() {
    set_panic_hook();
}

#[wasm_bindgen]
pub fn next_codepoint(codepoint: u32) -> u32 {
    if codepoint != 0x10FFFF {
        codepoint + 1
    } else {
        0
    }
}

#[wasm_bindgen]
pub fn previous_codepoint(codepoint: u32) -> u32 {
    if codepoint != 0 {
        codepoint - 1
    } else {
        0x10FFFF
    }
}

#[derive(Copy, Clone, Serialize)]
struct IdeographicVariationSequence {
    base_codepoint: u32,      // base codepoint
    variation_selector: u32,  // variation selector
    collection: &'static str, // collection
    item: &'static str,       // item, i.e. index into collection
}

#[wasm_bindgen]
pub fn variation_sequences_for_codepoint(codepoint: u32) -> String {
    let mut result = Vec::<IdeographicVariationSequence>::new();
    for ivd in IVD_SEQUENCES.iter() {
        if ivd.base_codepoint == codepoint {
            result.push(ivd.clone());
        }
    }
    serde_json::to_string(&result).unwrap()
}

#[wasm_bindgen]
pub fn u8toc(utf8_bytes: Vec<u8>) -> Option<Vec<u32>> {
    match std::str::from_utf8(utf8_bytes.as_slice()) {
        Err(_) => None,
        Ok(s) => Some(s.chars().map(|ch| u32::from(ch)).collect()),
    }
}

#[wasm_bindgen]
pub fn ctou8(codepoints: Vec<u32>) -> Option<Vec<u8>> {
    Some(ctos(codepoints)?.bytes().collect())
}

#[wasm_bindgen]
pub fn ctos(codepoints: Vec<u32>) -> Option<String> {
    let maybe_a_string = codepoints
        .iter()
        .map(|num| char::try_from(*num))
        .collect::<Result<String, _>>();
    match maybe_a_string {
        Err(_) => None,
        Ok(s) => Some(s),
    }
}

#[wasm_bindgen]
pub fn stoc(str: &str) -> Vec<u32> {
    str.chars().map(|ch| ch as u32).collect()
}

#[derive(Clone, Serialize)]
pub struct EncodingResult {
    pub success: bool,
    pub encoded_code_units: Option<Vec<u32>>,
    pub first_invalid_codepoint: Option<u32>,
}

// map codepoints -> code units
pub type EncodingTable = HashMap<u32, u32>;

// lazy_static! {
//     static ref ENCODING_TABLES: HashMap<&'static str, EncodingTable> = {
//         let mut encoding_table = HashMap::new();
//         encoding_table.insert("ASCII", [(0, 0), (1, 1)]);
//         encoding_table
//     };
// }

fn encode_str_internal(encoding_name: &str, codepoints: Vec<u32>) -> EncodingResult {
    let code_units: Result<Vec<u32>, u32> = match encoding_name {
        "Unicode UTF-8" => codepoints
            .iter()
            .map(|&cp| char::try_from(cp).map_err(|_| cp).map(|c| c as u32))
            .collect(),
        "Unicode UTF-32 (32-bit code units)" => codepoints
            .iter()
            .map(|&cp| {
                if (cp >= 0xd800 && cp <= 0xdfff) || cp > 0x10ffff {
                    Err(cp)
                } else {
                    Ok(cp)
                }
            })
            .collect(),
        _ => {
            let encoding = match ENCODING_TABLES.get(encoding_name) {
                Some(encoding) => encoding,
                None => {
                    return EncodingResult {
                        success: false,
                        encoded_code_units: None,
                        first_invalid_codepoint: None,
                    }
                }
            };
            codepoints
                .iter()
                .map(|&codepoint| {
                    encoding
                        .get(&codepoint)
                        .ok_or(codepoint)
                        .map(|code_unit| *code_unit)
                })
                .collect()
        }
    };
    match code_units {
        Ok(code_units) => EncodingResult {
            success: true,
            encoded_code_units: Some(
                code_units
                    .iter()
                    .copied()
                    .flat_map(|cu| {
                        if cu <= 0xff {
                            vec![cu]
                        } else {
                            vec![cu >> 8, cu & 0xff]
                        }
                    })
                    .collect(),
            ),
            first_invalid_codepoint: None,
        },
        Err(codepoint) => EncodingResult {
            success: false,
            encoded_code_units: None,
            first_invalid_codepoint: Some(codepoint),
        },
    }
}

#[wasm_bindgen]
pub fn encode_str(encoding_name: &str, codepoints: Vec<u32>) -> String {
    let result = encode_str_internal(encoding_name, codepoints);
    serde_json::to_string(&result).unwrap()
}

fn lookup_code_unit(table: &EncodingTable, code_unit: u32) -> Option<u32> {
    for (&k, &v) in table {
        if v == code_unit {
            return Some(k);
        }
    }
    None
}

#[wasm_bindgen]
pub fn decode_str(encoding_name: &str, code_units: Vec<u32>) -> Option<Vec<u32>> {
    if encoding_name == "Unicode UTF-8" {
        return u8toc(
            code_units
                .iter()
                .map(|u| if *u <= 0xff { Some(*u as u8) } else { None })
                .collect::<Option<Vec<u8>>>()?,
        );
    } else if encoding_name == "Unicode UTF-32 (32-bit code units)" {
        return code_units
            .iter()
            .map(|&u| {
                if (u >= 0xd800 && u <= 0xdfff) || u > 0x10ffff {
                    None
                } else {
                    Some(u)
                }
            })
            .collect::<Option<Vec<u32>>>();
    }
    let table = ENCODING_TABLES.get(encoding_name)?;
    let mut res: Vec<u32> = vec![];
    let mut try_combined = false;
    for (i, cu) in code_units.iter().enumerate() {
        if try_combined {
            match lookup_code_unit(table, code_units[i - 1] << 8 | cu) {
                Some(cp) => {
                    res.push(cp);
                    try_combined = false;
                }
                None => return None,
            }
        } else {
            match lookup_code_unit(table, *cu) {
                Some(cp) => res.push(cp),
                None => try_combined = true,
            }
        }
    }
    return Some(res);
}

#[wasm_bindgen]
pub fn long_category_name_for_short_name(short_name: &str) -> Option<String> {
    use std::str::FromStr;
    use unicode_rs::general_category::GeneralCategory;

    Some(
        GeneralCategory::from_str(short_name)
            .ok()?
            .long_name()
            .to_string(),
    )
}

#[wasm_bindgen]
pub fn basic_type_for_codepoint(
    short_general_category_name: &str,
    codepoint: u32,
) -> Option<String> {
    use std::str::FromStr;
    use unicode_rs::general_category::GeneralCategory;

    Some(
        GeneralCategory::from_str(short_general_category_name)
            .ok()?
            .codepoint_type(codepoint)
            .to_string(),
    )
}
<|endoftext|>


<commit_before>// Copyright 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0

use std::fmt;

use serde_json::Value;

/// The Mmds is the Microvm Metadata Service represented as an untyped json.
#[derive(Clone)]
pub struct Mmds {
    data_store: Value,
    is_initialized: bool,
}

#[derive(Debug, PartialEq)]
pub enum Error {
    NotFound,
    UnsupportedValueType,
}

impl fmt::Display for Error {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            Error::NotFound => write!(f, "The MMDS resource does not exist."),
            Error::UnsupportedValueType => {
                write!(f, "Cannot add non-strings values to the MMDS data-store.")
            }
        }
    }
}

impl Default for Mmds {
    fn default() -> Self {
        Mmds {
            data_store: Value::default(),
            is_initialized: false,
        }
    }
}

impl Mmds {
    /// This method is needed to check if data store is initialized.
    /// When a PATCH request is made on an uninitialized Mmds structure this method
    /// should return a NotFound error.
    fn check_data_store_initialized(&self) -> Result<(), Error> {
        if self.is_initialized {
            Ok(())
        } else {
            Err(Error::NotFound)
        }
    }

    /// This method validates the data from a PATCH or PUT request and returns
    /// an UnsupportedValueType error if the data contain any value type other than
    /// Strings, arrays and dictionaries.
    pub fn check_data_valid(data: &Value) -> Result<(), Error> {
        if let Some(map) = data.as_object() {
            for key in map.keys() {
                Mmds::check_data_valid(&map[key])?;
            }
        } else if let Some(array) = data.as_array() {
            for obj in array {
                Mmds::check_data_valid(&obj)?;
            }
        } else if !data.is_string() {
            return Err(Error::UnsupportedValueType);
        }
        Ok(())
    }

    pub fn put_data(&mut self, data: Value) -> Result<(), Error> {
        Mmds::check_data_valid(&data)?;
        self.data_store = data;
        self.is_initialized = true;
        Ok(())
    }

    pub fn patch_data(&mut self, patch_data: Value) -> Result<(), Error> {
        Mmds::check_data_valid(&patch_data)?;
        self.check_data_store_initialized()?;
        super::json_patch(&mut self.data_store, &patch_data);
        Ok(())
    }

    pub fn get_data_str(&self) -> String {
        if self.data_store.is_null() {
            return String::from("{}");
        }
        self.data_store.to_string()
    }

    /// This function replicates the behavior of the Instance Metadata Service
    /// https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/ec2-instance-metadata.html
    /// 1. For a (key, value) pair where the value is a dictionary, it will return all the keys
    /// in the dictionary.
    /// 2. For a (key, value) pair where the value is a simple type (bool, string, number),
    /// it will return the value.
    ///
    /// When the path is not found, a NotFound error is returned.
    pub fn get_value(&self, path: String) -> Result<Vec<String>, Error> {
        // The pointer function splits the input by "/". With a trailing "/", pointer does not
        // know how to get the object.
        let value = if path.ends_with('/') {
            self.data_store.pointer(&path.as_str()[..(path.len() - 1)])
        } else {
            self.data_store.pointer(path.as_str())
        };

        match value {
            Some(val) => {
                let mut ret = Vec::new();
                // If the `dict` is Value::Null, Error::NotFound is thrown.
                // If the `dict` is not a dictionary, a Vec with the value corresponding to
                // the key is returned.
                match val.as_object() {
                    Some(map) => {
                        // When the object is a map, push all the keys in the Vec.
                        for key in map.keys() {
                            let mut key = key.clone();
                            // If the key corresponds to a dictionary, a "/" is appended
                            // to the key name.
                            if map[&key].is_object() {
                                key.push_str("/");
                            }

                            ret.push(key);
                        }
                        Ok(ret)
                    }
                    None => {
                        // When the object is not a map, return the value.
                        // The only supported Value type is String.
                        match val.as_str() {
                            Some(str_val) => {
                                ret.push(str_val.to_string());
                                Ok(ret)
                            }
                            None => Err(Error::UnsupportedValueType),
                        }
                    }
                }
            }
            None => Err(Error::NotFound),
        }
    }
}

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

    #[test]
    fn test_mmds() {
        let mut mmds = Mmds::default();

        assert_eq!(
            mmds.check_data_store_initialized().unwrap_err().to_string(),
            "The MMDS resource does not exist.".to_string(),
        );

        let mut mmds_json = "{\"meta-data\":{\"iam\":\"dummy\"},\"user-data\":\"1522850095\"}";

        mmds.put_data(serde_json::from_str(mmds_json).unwrap())
            .unwrap();
        assert!(mmds.check_data_store_initialized().is_ok());

        assert_eq!(mmds.get_data_str(), mmds_json);

        // update the user-data field add test that patch works as expected
        let patch_json = "{\"user-data\":\"10\"}";
        mmds.patch_data(serde_json::from_str(patch_json).unwrap())
            .unwrap();
        mmds_json = "{\"meta-data\":{\"iam\":\"dummy\"},\"user-data\":\"10\"}";
        assert_eq!(mmds.get_data_str(), mmds_json);
    }

    #[test]
    fn test_get_value() {
        let mut mmds = Mmds::default();
        let data = r#"{
            "name": {
                "first": "John",
                "second": "Doe"
            },
            "age": "43",
            "phones": {
                "home": {
                    "RO": "+40 1234567",
                    "UK": "+44 1234567"
                },
                "mobile": "+44 2345678"
            }
        }"#;

        let data_store: Value = serde_json::from_str(data).unwrap();
        mmds.put_data(data_store).unwrap();

        // Test invalid path.
        assert_eq!(
            mmds.get_value("/invalid_path".to_string()),
            Err(Error::NotFound)
        );
        assert_eq!(
            mmds.get_value("/invalid_path/".to_string()),
            Err(Error::NotFound)
        );

        // Test path ends with /; Value is a dictionary.
        assert_eq!(
            mmds.get_value("/phones/".to_string()).unwrap(),
            vec!["home/", "mobile"]
        );

        assert_eq!(
            mmds.get_value("/phones/home/".to_string()).unwrap(),
            vec!["RO", "UK"]
        );

        // Test path ends with /; Value is a String.
        assert_eq!(
            mmds.get_value("/phones/mobile/".to_string()).unwrap(),
            vec!["+44 2345678"]
        );

        // Test path does NOT end with /; Value is a dictionary.
        assert_eq!(
            mmds.get_value("/phones".to_string()).unwrap(),
            vec!["home/", "mobile"]
        );

        // Test path does NOT end with /; Value is a String.
        assert_eq!(
            mmds.get_value("/phones/mobile".to_string()).unwrap(),
            vec!["+44 2345678"]
        );
    }

    #[test]
    fn test_get_element_from_array() {
        let mut mmds = Mmds::default();
        let data = r#"{
            "phones": [
                "+40 1234567",
                "+44 1234567"
            ]
        }"#;

        let data_store: Value = serde_json::from_str(data).unwrap();
        mmds.put_data(data_store).unwrap();

        // Test path does NOT end with /; Value is a String.
        assert_eq!(
            mmds.get_value("/phones/0".to_string()).unwrap(),
            vec!["+40 1234567"]
        );
    }

    #[test]
    fn test_update_data_store() {
        let mut mmds = Mmds::default();

        let data = r#"{
            "name": {
                "first": "John",
                "second": "Doe"
            },
            "age": "43"
        }"#;
        let data_store: Value = serde_json::from_str(data).unwrap();
        assert!(mmds.put_data(data_store).is_ok());

        let data = r#"{
            "name": {
                "first": "John",
                "second": "Doe"
            },
            "age": "100"
        }"#;
        let data_store: Value = serde_json::from_str(data).unwrap();
        assert!(mmds.patch_data(data_store).is_ok());

        let data = r#"{
            "name": {
                "first": "John",
                "second": "Doe"
            },
            "age": 43
        }"#;
        let data_store: Value = serde_json::from_str(data).unwrap();
        assert_eq!(
            mmds.put_data(data_store).unwrap_err().to_string(),
            "Cannot add non-strings values to the MMDS data-store.".to_string()
        );

        let data = r#"{
            "name": {
                "first": "John",
                "second": true
            },
            "age": "43"
        }"#;
        let data_store: Value = serde_json::from_str(data).unwrap();
        assert_eq!(
            mmds.patch_data(data_store),
            Err(Error::UnsupportedValueType)
        );
    }
}
<commit_msg>mmds: try each value item in fn check_data_valid<commit_after>// Copyright 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0

use std::fmt;

use serde_json::Value;

/// The Mmds is the Microvm Metadata Service represented as an untyped json.
#[derive(Clone)]
pub struct Mmds {
    data_store: Value,
    is_initialized: bool,
}

#[derive(Debug, PartialEq)]
pub enum Error {
    NotFound,
    UnsupportedValueType,
}

impl fmt::Display for Error {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            Error::NotFound => write!(f, "The MMDS resource does not exist."),
            Error::UnsupportedValueType => {
                write!(f, "Cannot add non-strings values to the MMDS data-store.")
            }
        }
    }
}

impl Default for Mmds {
    fn default() -> Self {
        Mmds {
            data_store: Value::default(),
            is_initialized: false,
        }
    }
}

impl Mmds {
    /// This method is needed to check if data store is initialized.
    /// When a PATCH request is made on an uninitialized Mmds structure this method
    /// should return a NotFound error.
    fn check_data_store_initialized(&self) -> Result<(), Error> {
        if self.is_initialized {
            Ok(())
        } else {
            Err(Error::NotFound)
        }
    }

    /// This method validates the data from a PATCH or PUT request and returns
    /// an UnsupportedValueType error if the data contain any value type other than
    /// Strings, arrays and dictionaries.
    pub fn check_data_valid(data: &Value) -> Result<(), Error> {
        if data.is_string() {
            Ok(())
        } else if let Some(map) = data.as_object() {
            map.values()
                .try_for_each(|value| Mmds::check_data_valid(value))
        } else if let Some(array) = data.as_array() {
            array
                .iter()
                .try_for_each(|value| Mmds::check_data_valid(value))
        } else {
            Err(Error::UnsupportedValueType)
        }
    }

    pub fn put_data(&mut self, data: Value) -> Result<(), Error> {
        Mmds::check_data_valid(&data)?;
        self.data_store = data;
        self.is_initialized = true;
        Ok(())
    }

    pub fn patch_data(&mut self, patch_data: Value) -> Result<(), Error> {
        Mmds::check_data_valid(&patch_data)?;
        self.check_data_store_initialized()?;
        super::json_patch(&mut self.data_store, &patch_data);
        Ok(())
    }

    pub fn get_data_str(&self) -> String {
        if self.data_store.is_null() {
            return String::from("{}");
        }
        self.data_store.to_string()
    }

    /// This function replicates the behavior of the Instance Metadata Service
    /// https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/ec2-instance-metadata.html
    /// 1. For a (key, value) pair where the value is a dictionary, it will return all the keys
    /// in the dictionary.
    /// 2. For a (key, value) pair where the value is a simple type (bool, string, number),
    /// it will return the value.
    ///
    /// When the path is not found, a NotFound error is returned.
    pub fn get_value(&self, path: String) -> Result<Vec<String>, Error> {
        // The pointer function splits the input by "/". With a trailing "/", pointer does not
        // know how to get the object.
        let value = if path.ends_with('/') {
            self.data_store.pointer(&path.as_str()[..(path.len() - 1)])
        } else {
            self.data_store.pointer(path.as_str())
        };

        match value {
            Some(val) => {
                let mut ret = Vec::new();
                // If the `dict` is Value::Null, Error::NotFound is thrown.
                // If the `dict` is not a dictionary, a Vec with the value corresponding to
                // the key is returned.
                match val.as_object() {
                    Some(map) => {
                        // When the object is a map, push all the keys in the Vec.
                        for key in map.keys() {
                            let mut key = key.clone();
                            // If the key corresponds to a dictionary, a "/" is appended
                            // to the key name.
                            if map[&key].is_object() {
                                key.push_str("/");
                            }

                            ret.push(key);
                        }
                        Ok(ret)
                    }
                    None => {
                        // When the object is not a map, return the value.
                        // The only supported Value type is String.
                        match val.as_str() {
                            Some(str_val) => {
                                ret.push(str_val.to_string());
                                Ok(ret)
                            }
                            None => Err(Error::UnsupportedValueType),
                        }
                    }
                }
            }
            None => Err(Error::NotFound),
        }
    }
}

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

    #[test]
    fn test_mmds() {
        let mut mmds = Mmds::default();

        assert_eq!(
            mmds.check_data_store_initialized().unwrap_err().to_string(),
            "The MMDS resource does not exist.".to_string(),
        );

        let mut mmds_json = "{\"meta-data\":{\"iam\":\"dummy\"},\"user-data\":\"1522850095\"}";

        mmds.put_data(serde_json::from_str(mmds_json).unwrap())
            .unwrap();
        assert!(mmds.check_data_store_initialized().is_ok());

        assert_eq!(mmds.get_data_str(), mmds_json);

        // update the user-data field add test that patch works as expected
        let patch_json = "{\"user-data\":\"10\"}";
        mmds.patch_data(serde_json::from_str(patch_json).unwrap())
            .unwrap();
        mmds_json = "{\"meta-data\":{\"iam\":\"dummy\"},\"user-data\":\"10\"}";
        assert_eq!(mmds.get_data_str(), mmds_json);
    }

    #[test]
    fn test_get_value() {
        let mut mmds = Mmds::default();
        let data = r#"{
            "name": {
                "first": "John",
                "second": "Doe"
            },
            "age": "43",
            "phones": {
                "home": {
                    "RO": "+40 1234567",
                    "UK": "+44 1234567"
                },
                "mobile": "+44 2345678"
            }
        }"#;

        let data_store: Value = serde_json::from_str(data).unwrap();
        mmds.put_data(data_store).unwrap();

        // Test invalid path.
        assert_eq!(
            mmds.get_value("/invalid_path".to_string()),
            Err(Error::NotFound)
        );
        assert_eq!(
            mmds.get_value("/invalid_path/".to_string()),
            Err(Error::NotFound)
        );

        // Test path ends with /; Value is a dictionary.
        assert_eq!(
            mmds.get_value("/phones/".to_string()).unwrap(),
            vec!["home/", "mobile"]
        );

        assert_eq!(
            mmds.get_value("/phones/home/".to_string()).unwrap(),
            vec!["RO", "UK"]
        );

        // Test path ends with /; Value is a String.
        assert_eq!(
            mmds.get_value("/phones/mobile/".to_string()).unwrap(),
            vec!["+44 2345678"]
        );

        // Test path does NOT end with /; Value is a dictionary.
        assert_eq!(
            mmds.get_value("/phones".to_string()).unwrap(),
            vec!["home/", "mobile"]
        );

        // Test path does NOT end with /; Value is a String.
        assert_eq!(
            mmds.get_value("/phones/mobile".to_string()).unwrap(),
            vec!["+44 2345678"]
        );
    }

    #[test]
    fn test_get_element_from_array() {
        let mut mmds = Mmds::default();
        let data = r#"{
            "phones": [
                "+40 1234567",
                "+44 1234567"
            ]
        }"#;

        let data_store: Value = serde_json::from_str(data).unwrap();
        mmds.put_data(data_store).unwrap();

        // Test path does NOT end with /; Value is a String.
        assert_eq!(
            mmds.get_value("/phones/0".to_string()).unwrap(),
            vec!["+40 1234567"]
        );
    }

    #[test]
    fn test_update_data_store() {
        let mut mmds = Mmds::default();

        let data = r#"{
            "name": {
                "first": "John",
                "second": "Doe"
            },
            "age": "43"
        }"#;
        let data_store: Value = serde_json::from_str(data).unwrap();
        assert!(mmds.put_data(data_store).is_ok());

        let data = r#"{
            "name": {
                "first": "John",
                "second": "Doe"
            },
            "age": "100"
        }"#;
        let data_store: Value = serde_json::from_str(data).unwrap();
        assert!(mmds.patch_data(data_store).is_ok());

        let data = r#"{
            "name": {
                "first": "John",
                "second": "Doe"
            },
            "age": 43
        }"#;
        let data_store: Value = serde_json::from_str(data).unwrap();
        assert_eq!(
            mmds.put_data(data_store).unwrap_err().to_string(),
            "Cannot add non-strings values to the MMDS data-store.".to_string()
        );

        let data = r#"{
            "name": {
                "first": "John",
                "second": true
            },
            "age": "43"
        }"#;
        let data_store: Value = serde_json::from_str(data).unwrap();
        assert_eq!(
            mmds.patch_data(data_store),
            Err(Error::UnsupportedValueType)
        );
    }
}
<|endoftext|>


<commit_before>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

use dom::attr::Attr;
use dom::bindings::cell::DOMRefCell;
use dom::bindings::codegen::Bindings::EventHandlerBinding::EventHandlerNonNull;
use dom::bindings::codegen::Bindings::HTMLBodyElementBinding::{self, HTMLBodyElementMethods};
use dom::bindings::codegen::Bindings::WindowBinding::WindowMethods;
use dom::bindings::codegen::InheritTypes::{EventTargetCast};
use dom::bindings::codegen::InheritTypes::{HTMLBodyElementDerived, HTMLElementCast};
use dom::bindings::js::Root;
use dom::bindings::utils::Reflectable;
use dom::document::Document;
use dom::element::{AttributeMutation, ElementTypeId};
use dom::eventtarget::{EventTarget, EventTargetTypeId};
use dom::htmlelement::{HTMLElement, HTMLElementTypeId};
use dom::node::{Node, NodeTypeId, window_from_node, document_from_node};
use dom::virtualmethods::VirtualMethods;
use msg::constellation_msg::ConstellationChan;
use msg::constellation_msg::Msg as ConstellationMsg;

use cssparser::RGBA;
use url::{Url, UrlParser};
use util::str::{self, DOMString};

use std::borrow::ToOwned;
use std::cell::Cell;
use std::rc::Rc;
use time;

/// How long we should wait before performing the initial reflow after `<body>` is parsed, in
/// nanoseconds.
const INITIAL_REFLOW_DELAY: u64 = 200_000_000;

#[dom_struct]
pub struct HTMLBodyElement {
    htmlelement: HTMLElement,
    background_color: Cell<Option<RGBA>>,
    background: DOMRefCell<Option<Url>>
}

impl HTMLBodyElementDerived for EventTarget {
    fn is_htmlbodyelement(&self) -> bool {
        *self.type_id() == EventTargetTypeId::Node(NodeTypeId::Element(ElementTypeId::HTMLElement(
                    HTMLElementTypeId::HTMLBodyElement)))
    }
}

impl HTMLBodyElement {
    fn new_inherited(localName: DOMString, prefix: Option<DOMString>, document: &Document)
                     -> HTMLBodyElement {
        HTMLBodyElement {
            htmlelement: HTMLElement::new_inherited(HTMLElementTypeId::HTMLBodyElement,
                                                    localName,
                                                    prefix,
                                                    document),
            background_color: Cell::new(None),
            background: DOMRefCell::new(None)
        }
    }

    #[allow(unrooted_must_root)]
    pub fn new(localName: DOMString, prefix: Option<DOMString>, document: &Document)
               -> Root<HTMLBodyElement> {
        let element = HTMLBodyElement::new_inherited(localName, prefix, document);
        Node::reflect_node(box element, document, HTMLBodyElementBinding::Wrap)
    }
}

impl HTMLBodyElementMethods for HTMLBodyElement {
    // https://html.spec.whatwg.org/multipage#dom-body-bgcolor
    make_getter!(BgColor, "bgcolor");

    // https://html.spec.whatwg.org/multipage#dom-body-bgcolor
    make_setter!(SetBgColor, "bgcolor");

    // https://html.spec.whatwg.org/multipage/#the-body-element
    fn GetOnunload(&self) -> Option<Rc<EventHandlerNonNull>> {
        let win = window_from_node(self);
        win.r().GetOnunload()
    }

    // https://html.spec.whatwg.org/multipage/#the-body-element
    fn SetOnunload(&self, listener: Option<Rc<EventHandlerNonNull>>) {
        let win = window_from_node(self);
        win.r().SetOnunload(listener)
    }
}

impl HTMLBodyElement {
    pub fn get_background_color(&self) -> Option<RGBA> {
        self.background_color.get()
    }

    #[allow(unsafe_code)]
    pub fn get_background(&self) -> Option<Url> {
        unsafe {
            self.background.borrow_for_layout().clone()
        }
    }
}

impl VirtualMethods for HTMLBodyElement {
    fn super_type<'b>(&'b self) -> Option<&'b VirtualMethods> {
        let element: &HTMLElement = HTMLElementCast::from_ref(self);
        Some(element as &VirtualMethods)
    }

    fn bind_to_tree(&self, tree_in_doc: bool) {
        if let Some(ref s) = self.super_type() {
            s.bind_to_tree(tree_in_doc);
        }

        if !tree_in_doc {
            return
        }

        let window = window_from_node(self);
        let document = window.r().Document();
        document.r().set_reflow_timeout(time::precise_time_ns() + INITIAL_REFLOW_DELAY);
        let ConstellationChan(ref chan) = window.r().constellation_chan();
        let event = ConstellationMsg::HeadParsed;
        chan.send(event).unwrap();
    }

    fn attribute_mutated(&self, attr: &Attr, mutation: AttributeMutation) {
        self.super_type().unwrap().attribute_mutated(attr, mutation);
        match (attr.local_name(), mutation) {
            (&atom!(bgcolor), _) => {
                self.background_color.set(mutation.new_value(attr).and_then(|value| {
                    str::parse_legacy_color(&value).ok()
                }));
            },
            (&atom!(background), _) => {
                *self.background.borrow_mut() = mutation.new_value(attr).and_then(|value| {
                    let base = document_from_node(self).url();
                    UrlParser::new().base_url(&base).parse(&value).ok()
                });
            },
            (name, AttributeMutation::Set(_)) if name.starts_with("on") => {
                static FORWARDED_EVENTS: &'static [&'static str] =
                    &["onfocus", "onload", "onscroll", "onafterprint", "onbeforeprint",
                      "onbeforeunload", "onhashchange", "onlanguagechange", "onmessage",
                      "onoffline", "ononline", "onpagehide", "onpageshow", "onpopstate",
                      "onstorage", "onresize", "onunload", "onerror"];
                let window = window_from_node(self);
                let (cx, url, reflector) = (window.get_cx(),
                                            window.get_url(),
                                            window.reflector().get_jsobject());
                let evtarget =
                    if FORWARDED_EVENTS.iter().any(|&event| &**name == event) {
                        EventTargetCast::from_ref(window.r())
                    } else {
                        EventTargetCast::from_ref(self)
                    };
                evtarget.set_event_handler_uncompiled(cx, url, reflector,
                                                      &name[2..],
                                                      (**attr.value()).to_owned());
            },
            _ => {}
        }
    }
}
<commit_msg>Match forwarded events as atoms, fixes #7495<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

use dom::attr::Attr;
use dom::bindings::cell::DOMRefCell;
use dom::bindings::codegen::Bindings::EventHandlerBinding::EventHandlerNonNull;
use dom::bindings::codegen::Bindings::HTMLBodyElementBinding::{self, HTMLBodyElementMethods};
use dom::bindings::codegen::Bindings::WindowBinding::WindowMethods;
use dom::bindings::codegen::InheritTypes::{EventTargetCast};
use dom::bindings::codegen::InheritTypes::{HTMLBodyElementDerived, HTMLElementCast};
use dom::bindings::js::Root;
use dom::bindings::utils::Reflectable;
use dom::document::Document;
use dom::element::{AttributeMutation, ElementTypeId};
use dom::eventtarget::{EventTarget, EventTargetTypeId};
use dom::htmlelement::{HTMLElement, HTMLElementTypeId};
use dom::node::{Node, NodeTypeId, window_from_node, document_from_node};
use dom::virtualmethods::VirtualMethods;
use msg::constellation_msg::ConstellationChan;
use msg::constellation_msg::Msg as ConstellationMsg;

use cssparser::RGBA;
use url::{Url, UrlParser};
use util::str::{self, DOMString};

use std::borrow::ToOwned;
use std::cell::Cell;
use std::rc::Rc;
use time;

/// How long we should wait before performing the initial reflow after `<body>` is parsed, in
/// nanoseconds.
const INITIAL_REFLOW_DELAY: u64 = 200_000_000;

#[dom_struct]
pub struct HTMLBodyElement {
    htmlelement: HTMLElement,
    background_color: Cell<Option<RGBA>>,
    background: DOMRefCell<Option<Url>>
}

impl HTMLBodyElementDerived for EventTarget {
    fn is_htmlbodyelement(&self) -> bool {
        *self.type_id() == EventTargetTypeId::Node(NodeTypeId::Element(ElementTypeId::HTMLElement(
                    HTMLElementTypeId::HTMLBodyElement)))
    }
}

impl HTMLBodyElement {
    fn new_inherited(localName: DOMString, prefix: Option<DOMString>, document: &Document)
                     -> HTMLBodyElement {
        HTMLBodyElement {
            htmlelement: HTMLElement::new_inherited(HTMLElementTypeId::HTMLBodyElement,
                                                    localName,
                                                    prefix,
                                                    document),
            background_color: Cell::new(None),
            background: DOMRefCell::new(None)
        }
    }

    #[allow(unrooted_must_root)]
    pub fn new(localName: DOMString, prefix: Option<DOMString>, document: &Document)
               -> Root<HTMLBodyElement> {
        let element = HTMLBodyElement::new_inherited(localName, prefix, document);
        Node::reflect_node(box element, document, HTMLBodyElementBinding::Wrap)
    }
}

impl HTMLBodyElementMethods for HTMLBodyElement {
    // https://html.spec.whatwg.org/multipage#dom-body-bgcolor
    make_getter!(BgColor, "bgcolor");

    // https://html.spec.whatwg.org/multipage#dom-body-bgcolor
    make_setter!(SetBgColor, "bgcolor");

    // https://html.spec.whatwg.org/multipage/#the-body-element
    fn GetOnunload(&self) -> Option<Rc<EventHandlerNonNull>> {
        let win = window_from_node(self);
        win.r().GetOnunload()
    }

    // https://html.spec.whatwg.org/multipage/#the-body-element
    fn SetOnunload(&self, listener: Option<Rc<EventHandlerNonNull>>) {
        let win = window_from_node(self);
        win.r().SetOnunload(listener)
    }
}

impl HTMLBodyElement {
    pub fn get_background_color(&self) -> Option<RGBA> {
        self.background_color.get()
    }

    #[allow(unsafe_code)]
    pub fn get_background(&self) -> Option<Url> {
        unsafe {
            self.background.borrow_for_layout().clone()
        }
    }
}

impl VirtualMethods for HTMLBodyElement {
    fn super_type<'b>(&'b self) -> Option<&'b VirtualMethods> {
        let element: &HTMLElement = HTMLElementCast::from_ref(self);
        Some(element as &VirtualMethods)
    }

    fn bind_to_tree(&self, tree_in_doc: bool) {
        if let Some(ref s) = self.super_type() {
            s.bind_to_tree(tree_in_doc);
        }

        if !tree_in_doc {
            return
        }

        let window = window_from_node(self);
        let document = window.r().Document();
        document.r().set_reflow_timeout(time::precise_time_ns() + INITIAL_REFLOW_DELAY);
        let ConstellationChan(ref chan) = window.r().constellation_chan();
        let event = ConstellationMsg::HeadParsed;
        chan.send(event).unwrap();
    }

    fn attribute_mutated(&self, attr: &Attr, mutation: AttributeMutation) {
        self.super_type().unwrap().attribute_mutated(attr, mutation);
        match (attr.local_name(), mutation) {
            (&atom!(bgcolor), _) => {
                self.background_color.set(mutation.new_value(attr).and_then(|value| {
                    str::parse_legacy_color(&value).ok()
                }));
            },
            (&atom!(background), _) => {
                *self.background.borrow_mut() = mutation.new_value(attr).and_then(|value| {
                    let base = document_from_node(self).url();
                    UrlParser::new().base_url(&base).parse(&value).ok()
                });
            },
            (name, AttributeMutation::Set(_)) if name.starts_with("on") => {
                let window = window_from_node(self);
                let (cx, url, reflector) = (window.get_cx(),
                                            window.get_url(),
                                            window.reflector().get_jsobject());
                let evtarget = match name {
                    &atom!(onfocus) | &atom!(onload) | &atom!(onscroll) | &atom!(onafterprint) |
                    &atom!(onbeforeprint) | &atom!(onbeforeunload) | &atom!(onhashchange) |
                    &atom!(onlanguagechange) | &atom!(onmessage) | &atom!(onoffline) | &atom!(ononline) |
                    &atom!(onpagehide) | &atom!(onpageshow) | &atom!(onpopstate) | &atom!(onstorage) |
                    &atom!(onresize) | &atom!(onunload) | &atom!(onerror)
                      => EventTargetCast::from_ref(window.r()), // forwarded event
                    _ => EventTargetCast::from_ref(self),
                };
                evtarget.set_event_handler_uncompiled(cx, url, reflector,
                                                      &name[2..],
                                                      (**attr.value()).to_owned());
            },
            _ => {}
        }
    }
}
<|endoftext|>


<commit_before>pub use self::pipe::Awakener;

/// Default *nix awakener implementation
mod pipe {
    use {io, Evented, EventSet, Poll, PollOpt, Token, TryRead, TryWrite};
    use unix::{self, PipeReader, PipeWriter};

    /*
     *
     * ===== Awakener =====
     *
     */

    pub struct Awakener {
        reader: PipeReader,
        writer: PipeWriter,
    }

    impl Awakener {
        pub fn new() -> io::Result<Awakener> {
            let (rd, wr) = try!(unix::pipe());

            Ok(Awakener {
                reader: rd,
                writer: wr,
            })
        }

        pub fn wakeup(&self) -> io::Result<()> {
            (&self.writer).try_write(b"0x01").map(|_| ())
        }

        pub fn cleanup(&self) {
            let mut buf = [0; 128];

            loop {
                // Consume data until all bytes are purged
                match (&self.reader).try_read(&mut buf) {
                    Ok(Some(i)) if i > 0 => {},
                    _ => return,
                }
            }
        }

        fn reader(&self) -> &PipeReader {
            &self.reader
        }
    }

    impl Evented for Awakener {
        fn register(&self, poll: &mut Poll, token: Token, interest: EventSet, opts: PollOpt) -> io::Result<()> {
            self.reader().register(poll, token, interest, opts)
        }

        fn reregister(&self, poll: &mut Poll, token: Token, interest: EventSet, opts: PollOpt) -> io::Result<()> {
            self.reader().reregister(poll, token, interest, opts)
        }

        fn deregister(&self, poll: &mut Poll) -> io::Result<()> {
            self.reader().deregister(poll)
        }
    }
}

/*

TODO: Bring back eventfd awakener.
      Blocked on carllerche/nix-rust#98
mod eventfd {
    use {io, Io, TryRead, TryWrite};
    use std::mem;
    use std::os::unix::io::{RawFd, AsRawFd};

    const MARK: &'static [u8] = b"0x000x000x000x000x000x000x000x01";

    mod nix {
        pub use nix::sys::eventfd::*;
    }

    pub struct Awakener {
        io: Io,
    }

    impl Awakener {
        pub fn new() -> io::Result<Awakener> {
            Ok(Awakener {
                io: Io::new(try!(eventfd())),
            })
        }

        pub fn wakeup(&self) -> io::Result<()> {
            unsafe {
                let io: &mut Io = mem::transmute(&self.io);

                io.write_slice(MARK)
                    .map(|_| ())
            }
        }

        pub fn as_raw_fd(&self) -> Fd {
            self.io.as_raw_fd()
        }

        pub fn cleanup(&self) {
            let mut buf = [0; 8];

            loop {
                unsafe {
                    let io: &mut Io = mem::transmute(&self.io);

                    // Consume data until all bytes are purged
                    match io.read_slice(&mut buf) {
                        Ok(Some(i)) if i > 0 => {},
                        _ => return,
                    }
                }
            }
        }
    }

    fn eventfd() -> io::Result<Fd> {
        nix::eventfd(0, nix::EFD_CLOEXEC | nix::EFD_NONBLOCK)
            .map_err(super::from_nix_error)
    }
}
 */
<commit_msg>Remove commented out code<commit_after>pub use self::pipe::Awakener;

/// Default *nix awakener implementation
mod pipe {
    use {io, Evented, EventSet, Poll, PollOpt, Token, TryRead, TryWrite};
    use unix::{self, PipeReader, PipeWriter};

    /*
     *
     * ===== Awakener =====
     *
     */

    pub struct Awakener {
        reader: PipeReader,
        writer: PipeWriter,
    }

    impl Awakener {
        pub fn new() -> io::Result<Awakener> {
            let (rd, wr) = try!(unix::pipe());

            Ok(Awakener {
                reader: rd,
                writer: wr,
            })
        }

        pub fn wakeup(&self) -> io::Result<()> {
            (&self.writer).try_write(b"0x01").map(|_| ())
        }

        pub fn cleanup(&self) {
            let mut buf = [0; 128];

            loop {
                // Consume data until all bytes are purged
                match (&self.reader).try_read(&mut buf) {
                    Ok(Some(i)) if i > 0 => {},
                    _ => return,
                }
            }
        }

        fn reader(&self) -> &PipeReader {
            &self.reader
        }
    }

    impl Evented for Awakener {
        fn register(&self, poll: &mut Poll, token: Token, interest: EventSet, opts: PollOpt) -> io::Result<()> {
            self.reader().register(poll, token, interest, opts)
        }

        fn reregister(&self, poll: &mut Poll, token: Token, interest: EventSet, opts: PollOpt) -> io::Result<()> {
            self.reader().reregister(poll, token, interest, opts)
        }

        fn deregister(&self, poll: &mut Poll) -> io::Result<()> {
            self.reader().deregister(poll)
        }
    }
}
<|endoftext|>


<commit_before>pub struct Node {
    pub word: Word,
    next: Option<Vec<Node>>,
    total: u32,
}

impl Node {
    pub fn new(w: Word) {
        Node{word:w, next: None, total:0}
    }
    pub fn add(&mut self, w: String) {
        self.total += 1;
        match self.next {
            None => {
                let vec = Vec::<Node>new();
                let n = Node::new(Word::fromString(w));
                vec.push(n);
                self.next = Some(vec);
            }
            Some(vec) => {
                let mut flag = false;
                //search for word
                for x in &vec {
                    //if we find the word, add one to part and total
                    if(x.word.value == w){
                        x.word.part = x.word.part + 1.0;
                        flag = true;
                    }
                }
                // if the word wasn't in there, create and add it
                if(!flag)
                {
                    let word = Word::fromString(w);
                }
            }
        }
    }
}

pub struct Word {
    pub value: String,
    pub part:  f32
}

impl Word {
    pub fn fromString(value: String) -> Word {
        Word{ value:value, part:1.0 }
    }
    pub fn new(value: &'static str) -> Word {
        Word{ value:String::from(value), part:1.0}
    }
    pub fn prob(&self, total: f32) -> f32 {
        return self.part/total;
    }
}

fn main() {
    let w = Word::new("test");
}
<commit_msg>Simple root node working<commit_after>#[derive(Debug)]
pub struct Root {
    next: Option<Vec<Node>>,
    total: u32,
}
impl Root{
    pub fn new() -> Root {
        Root{next: None, total:0}
    }
    pub fn add(&mut self, w: String) {
        self.total += 1;
        match self.next {
            None => {
                let mut vec: Vec<Node> = Vec::new();
                let n = Node::from_string(w);
                vec.push(n);
                self.next = Some(vec);
            }
            Some(ref mut vec) => {
                let mut flag = false;
                //search for word
                for x in vec.iter_mut() {
                    //if we find the word, add one to part and total
                    if x.word.value == w {
                        x.word.part = x.word.part + 1.0;
                        flag = true;
                    }
                }
                // if the word wasn't in there, create and add it
                if !flag
                {
                    let n = Node::from_string(w);
                    vec.push(n);
                }
            }
        }
    }
}
#[derive(Debug)]
pub struct Node {
    pub word: Word,
    next: Option<Vec<Node>>,
    total: u32,
}

impl Node {
    pub fn new(w: Word) -> Node {
        Node{word:w, next: None, total:1}
    }
    pub fn from_string(s: String) -> Node {
        Node{word:Word::from_string(s), next: None, total:1}
    }
    pub fn is_leaf(&self) -> bool {
        match self.next {
            None => return true,
            Some(ref vec)=> return vec.len() == 0,
        }
    }
    pub fn add(&mut self, w: String) {
        self.total += 1;
        match self.next {
            None => {
                let mut vec: Vec<Node> = Vec::new();
                let n = Node::from_string(w);
                vec.push(n);
                self.next = Some(vec);
            }
            Some(ref mut vec) => {
                let mut flag = false;
                //search for word
                for x in vec.iter_mut() {
                    //if we find the word, add one to part and total
                    if x.word.value == w {
                        x.word.part = x.word.part + 1.0;
                        flag = true;
                    }
                }
                // if the word wasn't in there, create and add it
                if !flag
                {
                    let n = Node::from_string(w);
                    vec.push(n);
                }
            }
        }
    }
}
#[derive(Debug)]
pub struct Word {
    pub value: String,
    pub part:  f32
}
impl Word {
    pub fn from_string(value: String) -> Word {
        Word{ value:value, part:1.0 }
    }
    pub fn new(value: &'static str) -> Word {
        Word{ value:String::from(value), part:1.0}
    }
    pub fn prob(&self, total: f32) -> f32 {
        return self.part/total;
    }
}

fn main() {
    let mut r = Root::new();
    r.add("test".to_string());
    r.add("test".to_string());
    r.add("post".to_string());
    println!("{:?}", r);
}
<|endoftext|>


<commit_before>use std::io;
use std::io::Write;
use std::process::Command;
use std::sync::Mutex;

use crate::error::print_error;
use crate::exit_codes::ExitCode;

struct Outputs {
    stdout: Vec<u8>,
    stderr: Vec<u8>,
}
struct OutputBuf<'a> {
    out_perm: &'a Mutex<()>,
    outputs: Vec<Outputs>,
}

impl<'a> OutputBuf<'a> {
    fn new(out_perm: &'a Mutex<()>) -> Self {
        Self {
            out_perm,
            outputs: Vec::new(),
        }
    }

    fn push(&mut self, stdout: Vec<u8>, stderr: Vec<u8>) {
        self.outputs.push(Outputs { stdout, stderr });
    }

    fn write(self) {
        // avoid taking the lock if there is nothing to do
        if self.outputs.is_empty() {
            return;
        }
        // While this lock is active, this thread will be the only thread allowed
        // to write its outputs.
        let _lock = self.out_perm.lock().unwrap();

        let stdout = io::stdout();
        let stderr = io::stderr();

        let mut stdout = stdout.lock();
        let mut stderr = stderr.lock();

        for output in self.outputs.iter() {
            let _ = stdout.write_all(&output.stdout);
            let _ = stderr.write_all(&output.stderr);
        }
    }
}

/// Executes a command.
pub fn execute_commands<I: Iterator<Item = Command>>(
    cmds: I,
    out_perm: &Mutex<()>,
    enable_output_buffering: bool,
) -> ExitCode {
    let mut out_buf = OutputBuf::new(out_perm);
    for mut cmd in cmds {
        // Spawn the supplied command.
        let output = if enable_output_buffering {
            cmd.output()
        } else {
            // If running on only one thread, don't buffer output
            // Allows for viewing and interacting with intermediate command output
            cmd.spawn().and_then(|c| c.wait_with_output())
        };

        // Then wait for the command to exit, if it was spawned.
        match output {
            Ok(output) => {
                if enable_output_buffering {
                    out_buf.push(output.stdout, output.stderr);
                }
                if output.status.code() != Some(0) {
                    out_buf.write();
                    return ExitCode::GeneralError;
                }
            }
            Err(why) => {
                out_buf.write();
                return handle_cmd_error(&cmd, why);
            }
        }
    }
    out_buf.write();
    ExitCode::Success
}

pub fn handle_cmd_error(cmd: &Command, err: io::Error) -> ExitCode {
    if err.kind() == io::ErrorKind::NotFound {
        print_error(format!("Command not found: {:?}", cmd));
        ExitCode::GeneralError
    } else {
        print_error(format!("Problem while executing command: {}", err));
        ExitCode::GeneralError
    }
}
<commit_msg>Use full names in command.rs<commit_after>use std::io;
use std::io::Write;
use std::process::Command;
use std::sync::Mutex;

use crate::error::print_error;
use crate::exit_codes::ExitCode;

struct Outputs {
    stdout: Vec<u8>,
    stderr: Vec<u8>,
}
struct OutputBuffer<'a> {
    output_permission: &'a Mutex<()>,
    outputs: Vec<Outputs>,
}

impl<'a> OutputBuffer<'a> {
    fn new(output_permission: &'a Mutex<()>) -> Self {
        Self {
            output_permission,
            outputs: Vec::new(),
        }
    }

    fn push(&mut self, stdout: Vec<u8>, stderr: Vec<u8>) {
        self.outputs.push(Outputs { stdout, stderr });
    }

    fn write(self) {
        // avoid taking the lock if there is nothing to do
        if self.outputs.is_empty() {
            return;
        }
        // While this lock is active, this thread will be the only thread allowed
        // to write its outputs.
        let _lock = self.output_permission.lock().unwrap();

        let stdout = io::stdout();
        let stderr = io::stderr();

        let mut stdout = stdout.lock();
        let mut stderr = stderr.lock();

        for output in self.outputs.iter() {
            let _ = stdout.write_all(&output.stdout);
            let _ = stderr.write_all(&output.stderr);
        }
    }
}

/// Executes a command.
pub fn execute_commands<I: Iterator<Item = Command>>(
    cmds: I,
    out_perm: &Mutex<()>,
    enable_output_buffering: bool,
) -> ExitCode {
    let mut output_buffer = OutputBuffer::new(out_perm);
    for mut cmd in cmds {
        // Spawn the supplied command.
        let output = if enable_output_buffering {
            cmd.output()
        } else {
            // If running on only one thread, don't buffer output
            // Allows for viewing and interacting with intermediate command output
            cmd.spawn().and_then(|c| c.wait_with_output())
        };

        // Then wait for the command to exit, if it was spawned.
        match output {
            Ok(output) => {
                if enable_output_buffering {
                    output_buffer.push(output.stdout, output.stderr);
                }
                if output.status.code() != Some(0) {
                    output_buffer.write();
                    return ExitCode::GeneralError;
                }
            }
            Err(why) => {
                output_buffer.write();
                return handle_cmd_error(&cmd, why);
            }
        }
    }
    output_buffer.write();
    ExitCode::Success
}

pub fn handle_cmd_error(cmd: &Command, err: io::Error) -> ExitCode {
    if err.kind() == io::ErrorKind::NotFound {
        print_error(format!("Command not found: {:?}", cmd));
        ExitCode::GeneralError
    } else {
        print_error(format!("Problem while executing command: {}", err));
        ExitCode::GeneralError
    }
}
<|endoftext|>


<commit_before>//extern crate serde_json;
use rustc_serialize::json;

use std::ffi::OsStr;
use std::fs::{ self, File };
use std::io::{ self, BufReader, Read };
use std::path::{ Path, PathBuf };

use download;
use verify;

macro_rules! custom_try {
    ($x:expr) => (match $x {
        Ok(x) => x,
        Err(why) => return Err(format!("An error occured during package finding. {}", why)),
    });
}

#[derive(RustcDecodable, RustcEncodable, Clone)]
pub struct Package {
    pub name: String,
    pub version: u32,
    pub crc32: u32,
    pub url: String,
    pub dependencies: Vec<Package>
}

#[derive(RustcDecodable, RustcEncodable)]
pub struct PackageList {
    packages: Vec<Package>,
    version: i32
}

pub fn update_package_list(url: &str, path: &Path) -> Result<bool, String> {
    if (path.extension().is_some() &&
        path.extension().unwrap_or(OsStr::new("")) != ".json") ||
       (path.extension().is_none())
    {
        return Err(String::from(
            format!("Extension of package list is not .json: {}", path.to_str().unwrap_or("Invalid File"))
        ));
    }

    let mut path_temp = PathBuf::new();
    path_temp.push(path);
    path_temp.set_extension("json.tmp");

    if download::download_file(url, path_temp.as_path()).is_err() {
        return Err(String::from("Error occured while downloading package list"))
    }

    if verify::verify_file_crc32(&custom_try!(File::open(&path_temp))) ==
       verify::verify_file_crc32(&custom_try!(File::open(&path)))
    {
        fs::remove_file(path_temp);
        return Ok(false)
    } else {
        fs::remove_file(path);
        fs::rename(path_temp, path);
        return Ok(true)
    }
}

pub fn find_package(name: &str, path:&Path) -> Result<Vec<Package>, String> {
    let mut list = custom_try!(File::open(path));
    let mut reader = BufReader::new(list);
    let mut buffer = String::new();

    reader.read_to_string(&mut buffer);
    let package_list: PackageList = custom_try!(json::decode(&buffer));

    let filtered = package_list.packages
                    .into_iter()
                    .filter(|x| !x.name.contains(name))
                    .collect::<Vec<_>>();

    match filtered.len() {
        0 => Err(String::from("Package not found")),
        _ => Ok(filtered)
    }
}

pub fn download_and_find(name: &str, url:&str, path:&Path) -> Result<Vec<Package>, String>{
    if update_package_list(url, path).is_ok() {
        return find_package(name, path)
    } else {
        return Err(String::from("Error occured while downloading package list"))
    }
}

pub fn select_package(name: &str, path: &Path) -> Result<Package, String>{
    let found_packages = find_package(name, path)?;

    if found_packages.len() > 1 {
        for (i, package) in found_packages.iter().enumerate() {
            println!("Package {}: {}", i, package.name);
        }

        let mut input = String::new();
        custom_try!(io::stdin().read_line(&mut input));
        let input: u16 = custom_try!(input.trim().parse::<u16>());

        if input > found_packages.len() as u16 {
            return Err(String::from("Invalid input"))
        } else {
            return Ok(found_packages[input as usize].clone())
        }
    } else {
        return Ok(found_packages[0].clone())
    }
}
<commit_msg>Remove unused mut.<commit_after>//extern crate serde_json;
use rustc_serialize::json;

use std::ffi::OsStr;
use std::fs::{ self, File };
use std::io::{ self, BufReader, Read };
use std::path::{ Path, PathBuf };

use download;
use verify;

macro_rules! custom_try {
    ($x:expr) => (match $x {
        Ok(x) => x,
        Err(why) => return Err(format!("An error occured during package finding. {}", why)),
    });
}

#[derive(RustcDecodable, RustcEncodable, Clone)]
pub struct Package {
    pub name: String,
    pub version: u32,
    pub crc32: u32,
    pub url: String,
    pub dependencies: Vec<Package>
}

#[derive(RustcDecodable, RustcEncodable)]
pub struct PackageList {
    packages: Vec<Package>,
    version: i32
}

pub fn update_package_list(url: &str, path: &Path) -> Result<bool, String> {
    if (path.extension().is_some() &&
        path.extension().unwrap_or(OsStr::new("")) != ".json") ||
       (path.extension().is_none())
    {
        return Err(String::from(
            format!("Extension of package list is not .json: {}", path.to_str().unwrap_or("Invalid File"))
        ));
    }

    let mut path_temp = PathBuf::new();
    path_temp.push(path);
    path_temp.set_extension("json.tmp");

    if download::download_file(url, path_temp.as_path()).is_err() {
        return Err(String::from("Error occured while downloading package list"))
    }

    if verify::verify_file_crc32(&custom_try!(File::open(&path_temp))) ==
       verify::verify_file_crc32(&custom_try!(File::open(&path)))
    {
        fs::remove_file(path_temp);
        return Ok(false)
    } else {
        fs::remove_file(path);
        fs::rename(path_temp, path);
        return Ok(true)
    }
}

pub fn find_package(name: &str, path:&Path) -> Result<Vec<Package>, String> {
    let list = custom_try!(File::open(path));
    let mut reader = BufReader::new(list);
    let mut buffer = String::new();

    reader.read_to_string(&mut buffer);
    let package_list: PackageList = custom_try!(json::decode(&buffer));

    let filtered = package_list.packages
                    .into_iter()
                    .filter(|x| !x.name.contains(name))
                    .collect::<Vec<_>>();

    match filtered.len() {
        0 => Err(String::from("Package not found")),
        _ => Ok(filtered)
    }
}

pub fn download_and_find(name: &str, url:&str, path:&Path) -> Result<Vec<Package>, String>{
    if update_package_list(url, path).is_ok() {
        return find_package(name, path)
    } else {
        return Err(String::from("Error occured while downloading package list"))
    }
}

pub fn select_package(name: &str, path: &Path) -> Result<Package, String>{
    let found_packages = find_package(name, path)?;

    if found_packages.len() > 1 {
        for (i, package) in found_packages.iter().enumerate() {
            println!("Package {}: {}", i, package.name);
        }

        let mut input = String::new();
        custom_try!(io::stdin().read_line(&mut input));
        let input: u16 = custom_try!(input.trim().parse::<u16>());

        if input > found_packages.len() as u16 {
            return Err(String::from("Invalid input"))
        } else {
            return Ok(found_packages[input as usize].clone())
        }
    } else {
        return Ok(found_packages[0].clone())
    }
}
<|endoftext|>