<commit_before>extern crate gimli;
extern crate getopts;
extern crate memmap;
extern crate object;

use object::Object;
use std::cell::Cell;
use std::env;
use std::io;
use std::io::Write;
use std::fs;
use std::process;

#[derive(Default)]
struct Flags {
    info: bool,
    line: bool,
    aranges: bool,
}

fn print_usage(opts: &getopts::Options) -> ! {
    let brief = format!("Usage: {} <options> <file>", env::args().next().unwrap());
    write!(&mut io::stderr(), "{}", opts.usage(&brief)).ok();
    process::exit(1);
}

fn main() {
    let mut opts = getopts::Options::new();
    opts.optflag("i", "", "print .debug_info and .debug_types sections");
    opts.optflag("l", "", "print .debug_line section");
    opts.optflag("r", "", "print .debug_aranges section");

    let matches = match opts.parse(env::args().skip(1)) {
        Ok(m) => m,
        Err(e) => {
            writeln!(&mut io::stderr(), "{:?}\n", e).ok();
            print_usage(&opts);
        }
    };
    if matches.free.is_empty() {
        print_usage(&opts);
    }

    let mut all = true;
    let mut flags = Flags::default();
    if matches.opt_present("i") {
        flags.info = true;
        all = false;
    }
    if matches.opt_present("l") {
        flags.line = true;
        all = false;
    }
    if matches.opt_present("r") {
        flags.aranges = true;
        all = false;
    }
    if all {
        flags.info = true;
        flags.line = true;
        flags.aranges = true;
    }

    for file_path in &matches.free {
        if matches.free.len() != 1 {
            println!("{}", file_path);
            println!("");
        }

        let file = fs::File::open(&file_path).expect("Should open file");
        let file = memmap::Mmap::open(&file, memmap::Protection::Read)
            .expect("Should create a mmap for file");
        let file = object::File::parse(unsafe { file.as_slice() });

        if file.is_little_endian() {
            dump_file::<gimli::LittleEndian>(file, &flags);
        } else {
            dump_file::<gimli::BigEndian>(file, &flags);
        }
    }
}

fn dump_file<Endian>(file: object::File, flags: &Flags)
    where Endian: gimli::Endianity
{
    let debug_abbrev = file.get_section(".debug_abbrev").unwrap_or(&[]);
    let debug_abbrev = gimli::DebugAbbrev::<Endian>::new(debug_abbrev);
    let debug_str = file.get_section(".debug_str").unwrap_or(&[]);
    let debug_str = gimli::DebugStr::<Endian>::new(debug_str);

    if flags.info {
        dump_info(&file, debug_abbrev, debug_str);
        dump_types(&file, debug_abbrev, debug_str);
    }
    if flags.line {
        dump_line(&file, debug_abbrev);
    }
    if flags.aranges {
        dump_aranges::<Endian>(&file);
    }
}

fn dump_info<Endian>(file: &object::File,
                     debug_abbrev: gimli::DebugAbbrev<Endian>,
                     debug_str: gimli::DebugStr<Endian>)
    where Endian: gimli::Endianity
{
    if let Some(debug_info) = file.get_section(".debug_info") {
        println!(".debug_info");
        println!("");

        let debug_info = gimli::DebugInfo::<Endian>::new(&debug_info);

        let mut iter = debug_info.units();
        while let Some(unit) = iter.next().expect("Should parse compilation unit") {
            let abbrevs = unit.abbreviations(debug_abbrev)
                .expect("Error parsing abbreviations");

            dump_entries(unit.entries(&abbrevs), debug_str);
        }
    }
}

fn dump_types<Endian>(file: &object::File,
                      debug_abbrev: gimli::DebugAbbrev<Endian>,
                      debug_str: gimli::DebugStr<Endian>)
    where Endian: gimli::Endianity
{
    if let Some(debug_types) = file.get_section(".debug_types") {
        println!(".debug_types");
        println!("");

        let debug_types = gimli::DebugTypes::<Endian>::new(&debug_types);

        let mut iter = debug_types.units();
        while let Some(unit) = iter.next().expect("Should parse the unit OK") {
            let abbrevs = unit.abbreviations(debug_abbrev)
                .expect("Error parsing abbreviations");

            dump_entries(unit.entries(&abbrevs), debug_str);
        }
    }
}

fn dump_entries<Endian>(mut entries: gimli::EntriesCursor<Endian>,
                        debug_str: gimli::DebugStr<Endian>)
    where Endian: gimli::Endianity
{
    let depth = Cell::new(0);
    while let Some((delta_depth, entry)) = entries.next_dfs().expect("Should parse next dfs") {
        depth.set(depth.get() + delta_depth);
        let indent = || {
            for _ in 0..(depth.get() as usize) {
                print!("        ");
            }
        };

        indent();
        println!("<{}> <{}>", entry.offset(), entry.tag());

        let mut attrs = entry.attrs();
        while let Some(attr) = attrs.next().expect("Should parse attribute OK") {
            indent();
            let mut value = attr.value();
            if let gimli::AttributeValue::DebugStrRef(o) = value {
                let s = debug_str.get_str(o).expect("Should have valid str offset");
                value = gimli::AttributeValue::String(s)
            }
            println!("    {} = {:?}", attr.name(), value);
        }
    }
}

fn dump_line<Endian>(file: &object::File, debug_abbrev: gimli::DebugAbbrev<Endian>)
    where Endian: gimli::Endianity
{
    let debug_line = file.get_section(".debug_line");
    let debug_info = file.get_section(".debug_info");

    if let (Some(debug_line), Some(debug_info)) = (debug_line, debug_info) {
        println!(".debug_line");
        println!("");

        let debug_line = gimli::DebugLine::<Endian>::new(&debug_line);
        let debug_info = gimli::DebugInfo::<Endian>::new(&debug_info);

        let mut iter = debug_info.units();
        while let Some(unit) = iter.next().expect("Should parse unit header OK") {
            let abbrevs = unit.abbreviations(debug_abbrev)
                .expect("Error parsing abbreviations");

            let mut cursor = unit.entries(&abbrevs);
            cursor.next_dfs().expect("Should parse next dfs");

            let root = cursor.current().expect("Should have a root DIE");
            let offset = match root.attr_value(gimli::DW_AT_stmt_list) {
                Some(gimli::AttributeValue::DebugLineRef(offset)) => offset,
                _ => continue,
            };

            let header =
                gimli::LineNumberProgramHeader::new(debug_line, offset, unit.address_size());
            if let Ok(header) = header {
                println!("");
                println!("Offset:                             0x{:x}", offset.0);
                println!("Length:                             {}",
                         header.unit_length());
                println!("DWARF version:                      {}", header.version());
                println!("Prologue length:                    {}",
                         header.header_length());
                println!("Minimum instruction length:         {}",
                         header.minimum_instruction_length());
                println!("Maximum operations per instruction: {}",
                         header.maximum_operations_per_instruction());
                println!("Default is_stmt:                    {}",
                         header.default_is_stmt());
                println!("Line base:                          {}", header.line_base());
                println!("Line range:                         {}",
                         header.line_range());
                println!("Opcode base:                        {}",
                         header.opcode_base());

                println!("");
                println!("Opcodes:");
                for (i, length) in header.standard_opcode_lengths().iter().enumerate() {
                    println!("  Opcode {} as {} args", i + 1, length);
                }

                println!("");
                println!("The Directory Table:");
                for (i, dir) in header.include_directories().iter().enumerate() {
                    println!("  {} {}", i + 1, dir.to_string_lossy());
                }

                println!("");
                println!("The File Name Table");
                println!("  Entry\tDir\tTime\tSize\tName");
                for (i, file) in header.file_names().iter().enumerate() {
                    println!("  {}\t{}\t{}\t{}\t{}",
                             i + 1,
                             file.directory_index(),
                             file.last_modification(),
                             file.length(),
                             file.path_name().to_string_lossy());
                }

                println!("");
                println!("Line Number Statements:");
                let mut opcodes = header.opcodes();
                while let Some(opcode) = opcodes.next_opcode(&header)
                    .expect("Should parse opcode OK") {
                    println!("  {}", opcode);
                }

                println!("");
                println!("Line Number Rows:");
                println!("<pc>        [lno,col]");
                let mut state_machine = gimli::StateMachine::new(header);
                let mut file_index = 0;
                while let Some(row) = state_machine.next_row()
                    .expect("Should parse row OK") {
                    let line = row.line().unwrap_or(0);
                    let column = match row.column() {
                        gimli::ColumnType::Column(column) => column,
                        gimli::ColumnType::LeftEdge => 0,
                    };
                    print!("0x{:08x}  [{:4},{:2}]", row.address(), line, column);
                    if row.is_stmt() {
                        print!(" NS");
                    }
                    if row.basic_block() {
                        print!(" BB");
                    }
                    if row.end_sequence() {
                        print!(" ET");
                    }
                    if row.prologue_end() {
                        print!(" PE");
                    }
                    if row.epilogue_begin() {
                        print!(" EB");
                    }
                    if row.isa() != 0 {
                        print!(" IS={}", row.isa());
                    }
                    if row.discriminator() != 0 {
                        print!(" DI={}", row.discriminator());
                    }
                    if file_index != row.file_index() {
                        file_index = row.file_index();
                        if let Ok(file) = row.file() {
                            if let Some(directory) = file.directory(row.header()) {
                                print!(" uri: \"{}/{}\"",
                                       directory.to_string_lossy(),
                                       file.path_name().to_string_lossy());
                            } else {
                                print!(" uri: \"{}\"", file.path_name().to_string_lossy());
                            }
                        }
                    }
                    println!("");
                }
            }
        }
    }
}

fn dump_aranges<Endian>(file: &object::File)
    where Endian: gimli::Endianity
{
    let debug_aranges = file.get_section(".debug_aranges");
    let debug_info = file.get_section(".debug_info");

    if let (Some(debug_aranges), Some(debug_info)) = (debug_aranges, debug_info) {
        println!(".debug_aranges");
        println!("");

        let debug_aranges = gimli::DebugAranges::<Endian>::new(debug_aranges);
        let debug_info = gimli::DebugInfo::<Endian>::new(debug_info);

        let mut cu_die_offset = gimli::DebugInfoOffset(0);
        let mut prev_cu_offset = None;
        let mut aranges = debug_aranges.items();
        while let Some(arange) = aranges.next().expect("Should parse arange OK") {
            let cu_offset = arange.debug_info_offset();
            if Some(cu_offset) != prev_cu_offset {
                let cu = debug_info.header_from_offset(cu_offset)
                    .expect("Should parse unit header OK");
                cu_die_offset = gimli::DebugInfoOffset(cu_offset.0 + cu.header_size() as u64);
                prev_cu_offset = Some(cu_offset);
            }
            if let Some(segment) = arange.segment() {
                print!("arange starts at seg,off 0x{:08x},0x{:08x}, ",
                       segment,
                       arange.address());
            } else {
                print!("arange starts at 0x{:08x}, ", arange.address());
            }
            println!("length of 0x{:08x}, cu_die_offset = 0x{:08x}",
                     arange.length(),
                     cu_die_offset.0);
        }
    }
}
<commit_msg>dwarfdump: delete unneeded Cell<commit_after>extern crate gimli;
extern crate getopts;
extern crate memmap;
extern crate object;

use object::Object;
use std::env;
use std::io;
use std::io::Write;
use std::fs;
use std::process;

#[derive(Default)]
struct Flags {
    info: bool,
    line: bool,
    aranges: bool,
}

fn print_usage(opts: &getopts::Options) -> ! {
    let brief = format!("Usage: {} <options> <file>", env::args().next().unwrap());
    write!(&mut io::stderr(), "{}", opts.usage(&brief)).ok();
    process::exit(1);
}

fn main() {
    let mut opts = getopts::Options::new();
    opts.optflag("i", "", "print .debug_info and .debug_types sections");
    opts.optflag("l", "", "print .debug_line section");
    opts.optflag("r", "", "print .debug_aranges section");

    let matches = match opts.parse(env::args().skip(1)) {
        Ok(m) => m,
        Err(e) => {
            writeln!(&mut io::stderr(), "{:?}\n", e).ok();
            print_usage(&opts);
        }
    };
    if matches.free.is_empty() {
        print_usage(&opts);
    }

    let mut all = true;
    let mut flags = Flags::default();
    if matches.opt_present("i") {
        flags.info = true;
        all = false;
    }
    if matches.opt_present("l") {
        flags.line = true;
        all = false;
    }
    if matches.opt_present("r") {
        flags.aranges = true;
        all = false;
    }
    if all {
        flags.info = true;
        flags.line = true;
        flags.aranges = true;
    }

    for file_path in &matches.free {
        if matches.free.len() != 1 {
            println!("{}", file_path);
            println!("");
        }

        let file = fs::File::open(&file_path).expect("Should open file");
        let file = memmap::Mmap::open(&file, memmap::Protection::Read)
            .expect("Should create a mmap for file");
        let file = object::File::parse(unsafe { file.as_slice() });

        if file.is_little_endian() {
            dump_file::<gimli::LittleEndian>(file, &flags);
        } else {
            dump_file::<gimli::BigEndian>(file, &flags);
        }
    }
}

fn dump_file<Endian>(file: object::File, flags: &Flags)
    where Endian: gimli::Endianity
{
    let debug_abbrev = file.get_section(".debug_abbrev").unwrap_or(&[]);
    let debug_abbrev = gimli::DebugAbbrev::<Endian>::new(debug_abbrev);
    let debug_str = file.get_section(".debug_str").unwrap_or(&[]);
    let debug_str = gimli::DebugStr::<Endian>::new(debug_str);

    if flags.info {
        dump_info(&file, debug_abbrev, debug_str);
        dump_types(&file, debug_abbrev, debug_str);
    }
    if flags.line {
        dump_line(&file, debug_abbrev);
    }
    if flags.aranges {
        dump_aranges::<Endian>(&file);
    }
}

fn dump_info<Endian>(file: &object::File,
                     debug_abbrev: gimli::DebugAbbrev<Endian>,
                     debug_str: gimli::DebugStr<Endian>)
    where Endian: gimli::Endianity
{
    if let Some(debug_info) = file.get_section(".debug_info") {
        println!(".debug_info");
        println!("");

        let debug_info = gimli::DebugInfo::<Endian>::new(&debug_info);

        let mut iter = debug_info.units();
        while let Some(unit) = iter.next().expect("Should parse compilation unit") {
            let abbrevs = unit.abbreviations(debug_abbrev)
                .expect("Error parsing abbreviations");

            dump_entries(unit.entries(&abbrevs), debug_str);
        }
    }
}

fn dump_types<Endian>(file: &object::File,
                      debug_abbrev: gimli::DebugAbbrev<Endian>,
                      debug_str: gimli::DebugStr<Endian>)
    where Endian: gimli::Endianity
{
    if let Some(debug_types) = file.get_section(".debug_types") {
        println!(".debug_types");
        println!("");

        let debug_types = gimli::DebugTypes::<Endian>::new(&debug_types);

        let mut iter = debug_types.units();
        while let Some(unit) = iter.next().expect("Should parse the unit OK") {
            let abbrevs = unit.abbreviations(debug_abbrev)
                .expect("Error parsing abbreviations");

            dump_entries(unit.entries(&abbrevs), debug_str);
        }
    }
}

fn dump_entries<Endian>(mut entries: gimli::EntriesCursor<Endian>,
                        debug_str: gimli::DebugStr<Endian>)
    where Endian: gimli::Endianity
{
    let mut depth = 0;
    while let Some((delta_depth, entry)) = entries.next_dfs().expect("Should parse next dfs") {
        depth += delta_depth;
        let indent = || {
            for _ in 0..depth as usize {
                print!("        ");
            }
        };

        indent();
        println!("<{}> <{}>", entry.offset(), entry.tag());

        let mut attrs = entry.attrs();
        while let Some(attr) = attrs.next().expect("Should parse attribute OK") {
            indent();
            let mut value = attr.value();
            if let gimli::AttributeValue::DebugStrRef(o) = value {
                let s = debug_str.get_str(o).expect("Should have valid str offset");
                value = gimli::AttributeValue::String(s)
            }
            println!("    {} = {:?}", attr.name(), value);
        }
    }
}

fn dump_line<Endian>(file: &object::File, debug_abbrev: gimli::DebugAbbrev<Endian>)
    where Endian: gimli::Endianity
{
    let debug_line = file.get_section(".debug_line");
    let debug_info = file.get_section(".debug_info");

    if let (Some(debug_line), Some(debug_info)) = (debug_line, debug_info) {
        println!(".debug_line");
        println!("");

        let debug_line = gimli::DebugLine::<Endian>::new(&debug_line);
        let debug_info = gimli::DebugInfo::<Endian>::new(&debug_info);

        let mut iter = debug_info.units();
        while let Some(unit) = iter.next().expect("Should parse unit header OK") {
            let abbrevs = unit.abbreviations(debug_abbrev)
                .expect("Error parsing abbreviations");

            let mut cursor = unit.entries(&abbrevs);
            cursor.next_dfs().expect("Should parse next dfs");

            let root = cursor.current().expect("Should have a root DIE");
            let offset = match root.attr_value(gimli::DW_AT_stmt_list) {
                Some(gimli::AttributeValue::DebugLineRef(offset)) => offset,
                _ => continue,
            };

            let header =
                gimli::LineNumberProgramHeader::new(debug_line, offset, unit.address_size());
            if let Ok(header) = header {
                println!("");
                println!("Offset:                             0x{:x}", offset.0);
                println!("Length:                             {}",
                         header.unit_length());
                println!("DWARF version:                      {}", header.version());
                println!("Prologue length:                    {}",
                         header.header_length());
                println!("Minimum instruction length:         {}",
                         header.minimum_instruction_length());
                println!("Maximum operations per instruction: {}",
                         header.maximum_operations_per_instruction());
                println!("Default is_stmt:                    {}",
                         header.default_is_stmt());
                println!("Line base:                          {}", header.line_base());
                println!("Line range:                         {}",
                         header.line_range());
                println!("Opcode base:                        {}",
                         header.opcode_base());

                println!("");
                println!("Opcodes:");
                for (i, length) in header.standard_opcode_lengths().iter().enumerate() {
                    println!("  Opcode {} as {} args", i + 1, length);
                }

                println!("");
                println!("The Directory Table:");
                for (i, dir) in header.include_directories().iter().enumerate() {
                    println!("  {} {}", i + 1, dir.to_string_lossy());
                }

                println!("");
                println!("The File Name Table");
                println!("  Entry\tDir\tTime\tSize\tName");
                for (i, file) in header.file_names().iter().enumerate() {
                    println!("  {}\t{}\t{}\t{}\t{}",
                             i + 1,
                             file.directory_index(),
                             file.last_modification(),
                             file.length(),
                             file.path_name().to_string_lossy());
                }

                println!("");
                println!("Line Number Statements:");
                let mut opcodes = header.opcodes();
                while let Some(opcode) = opcodes.next_opcode(&header)
                    .expect("Should parse opcode OK") {
                    println!("  {}", opcode);
                }

                println!("");
                println!("Line Number Rows:");
                println!("<pc>        [lno,col]");
                let mut state_machine = gimli::StateMachine::new(header);
                let mut file_index = 0;
                while let Some(row) = state_machine.next_row()
                    .expect("Should parse row OK") {
                    let line = row.line().unwrap_or(0);
                    let column = match row.column() {
                        gimli::ColumnType::Column(column) => column,
                        gimli::ColumnType::LeftEdge => 0,
                    };
                    print!("0x{:08x}  [{:4},{:2}]", row.address(), line, column);
                    if row.is_stmt() {
                        print!(" NS");
                    }
                    if row.basic_block() {
                        print!(" BB");
                    }
                    if row.end_sequence() {
                        print!(" ET");
                    }
                    if row.prologue_end() {
                        print!(" PE");
                    }
                    if row.epilogue_begin() {
                        print!(" EB");
                    }
                    if row.isa() != 0 {
                        print!(" IS={}", row.isa());
                    }
                    if row.discriminator() != 0 {
                        print!(" DI={}", row.discriminator());
                    }
                    if file_index != row.file_index() {
                        file_index = row.file_index();
                        if let Ok(file) = row.file() {
                            if let Some(directory) = file.directory(row.header()) {
                                print!(" uri: \"{}/{}\"",
                                       directory.to_string_lossy(),
                                       file.path_name().to_string_lossy());
                            } else {
                                print!(" uri: \"{}\"", file.path_name().to_string_lossy());
                            }
                        }
                    }
                    println!("");
                }
            }
        }
    }
}

fn dump_aranges<Endian>(file: &object::File)
    where Endian: gimli::Endianity
{
    let debug_aranges = file.get_section(".debug_aranges");
    let debug_info = file.get_section(".debug_info");

    if let (Some(debug_aranges), Some(debug_info)) = (debug_aranges, debug_info) {
        println!(".debug_aranges");
        println!("");

        let debug_aranges = gimli::DebugAranges::<Endian>::new(debug_aranges);
        let debug_info = gimli::DebugInfo::<Endian>::new(debug_info);

        let mut cu_die_offset = gimli::DebugInfoOffset(0);
        let mut prev_cu_offset = None;
        let mut aranges = debug_aranges.items();
        while let Some(arange) = aranges.next().expect("Should parse arange OK") {
            let cu_offset = arange.debug_info_offset();
            if Some(cu_offset) != prev_cu_offset {
                let cu = debug_info.header_from_offset(cu_offset)
                    .expect("Should parse unit header OK");
                cu_die_offset = gimli::DebugInfoOffset(cu_offset.0 + cu.header_size() as u64);
                prev_cu_offset = Some(cu_offset);
            }
            if let Some(segment) = arange.segment() {
                print!("arange starts at seg,off 0x{:08x},0x{:08x}, ",
                       segment,
                       arange.address());
            } else {
                print!("arange starts at 0x{:08x}, ", arange.address());
            }
            println!("length of 0x{:08x}, cu_die_offset = 0x{:08x}",
                     arange.length(),
                     cu_die_offset.0);
        }
    }
}
<|endoftext|>


<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, HashSet};

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

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 {
    if transaction.to.is_empty() {
        Transaction::ContractCreation {
            caller: Address::from_str(&transaction.from).unwrap(),
            value: U256::from_str(&transaction.value).unwrap(),
            gas_limit: Gas::from_str(&transaction.gas).unwrap(),
            gas_price: Gas::from_str(&transaction.gasPrice).unwrap(),
            init: read_hex(&transaction.input).unwrap(),
        }
    } else {
        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 from_rpc_log(log: &RPCLog) -> Log {
    let mut topics: Vec<M256> = Vec::new();
    for topic in &log.topics {
        topics.push(M256::from_str(&topic).unwrap());
    }
    Log {
        address: Address::from_str(&log.address).unwrap(),
        data: read_hex(&log.data).unwrap(),
        topics: topics,
    }
}

/// Accounts in this list should always be considered exists.
fn irregular_addresses(number: usize) -> HashSet<Address> {
    let config: HashMap<Address, usize> = {
        let mut config = HashMap::new();
        config.insert(Address::from_str("0x0000000000000000000000000000000000000000").unwrap(), 0);
        config.insert(Address::from_str("0x0000000000000000000000000000000000000001").unwrap(), 0);
        config.insert(Address::from_str("0x0000000000000000000000000000000000000002").unwrap(), 505137);
        config.insert(Address::from_str("0x0000000000000000000000000000000000000003").unwrap(), 0);
        config.insert(Address::from_str("0x0000000000000000000000000000000000000004").unwrap(), 0);

        config.insert(Address::from_str("0xbfe465e7eb5a2928b5bf22bef93ad06089dc6179").unwrap(), 229894);
        config.insert(Address::from_str("0xc7585b4ea1829ef37f2fcc6ceaa6063700000000").unwrap(), 188235);

        config
    };

    let mut result: HashSet<Address> = HashSet::new();
    for (key, value) in config {
        if number > value {
            result.insert(key);
        }
    }
    result
}

fn handle_fire(client: &mut GethRPCClient, vm: &mut SeqTransactionVM, last_block_number: &str,
               irregular_addresses: &HashSet<Address>) {
    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 = 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();
                if nonce == M256::zero() && balance == U256::zero() && code.len() == 0 &&
                    !irregular_addresses.contains(&address)
                {
                    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 = M256::from_str(&client.get_block_by_number(&format!("0x{:x}", number))
                                          .hash).unwrap();
                vm.commit_blockhash(number, hash);
            },
        }
    }
}

fn is_miner_or_uncle(address: Address, block: &RPCBlock, client: &mut GethRPCClient) -> 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(client: &mut GethRPCClient, number: usize) {
    let block = client.get_block_by_number(format!("0x{:x}", number).as_str());
    println!("block {}, transaction count: {}", block.number, block.transactions.len());
    let last_number = format!("0x{:x}", number - 1);
    let cur_number = block.number.to_string();
    let block_header = from_rpc_block(&block);
    let irregular_addresses = irregular_addresses(number);

    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(), &FRONTIER_PATCH)
        } else {
            SeqTransactionVM::with_previous(transaction, block_header.clone(), &FRONTIER_PATCH, last_vm.as_ref().unwrap())
        };

        handle_fire(client, &mut vm, &last_number, &irregular_addresses);

        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 {
                &Account::Full {
                    address,
                    balance,
                    ref changing_storage,
                    ..
                } => {
                    if !is_miner_or_uncle(address, &block, client) {
                        let expected_balance = client.get_balance(&format!("0x{:x}", address),
                                                                  &cur_number);
                        assert!(U256::from_str(&expected_balance).unwrap() == 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),
                                                                   &cur_number);
                        assert!(M256::from_str(&expected_value).unwrap() == value);
                    }
                },
                &Account::Create {
                    address,
                    balance,
                    ref storage,
                    ..
                } => {
                    if !is_miner_or_uncle(address, &block, client) {
                        let expected_balance = client.get_balance(&format!("0x{:x}", address),
                                                                  &cur_number);
                        assert!(U256::from_str(&expected_balance).unwrap() == balance);
                    }
                    let storage: HashMap<M256, 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);
                    }
                },
                &Account::IncreaseBalance(address, balance) => {
                    if !is_miner_or_uncle(address, &block, client) {
                        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());
                    }
                },
                &Account::DecreaseBalance(address, balance) => {
                    if !is_miner_or_uncle(address, &block, client) {
                        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 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`.")
    ).get_matches();

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

    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(&mut client, n);
        }
    } else {
        let number = usize::from_str_radix(&number, 10).unwrap();
        test_block(&mut client, number);
    }
}
<commit_msg>Irregular accounts: add<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, HashSet};

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

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 {
    if transaction.to.is_empty() {
        Transaction::ContractCreation {
            caller: Address::from_str(&transaction.from).unwrap(),
            value: U256::from_str(&transaction.value).unwrap(),
            gas_limit: Gas::from_str(&transaction.gas).unwrap(),
            gas_price: Gas::from_str(&transaction.gasPrice).unwrap(),
            init: read_hex(&transaction.input).unwrap(),
        }
    } else {
        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 from_rpc_log(log: &RPCLog) -> Log {
    let mut topics: Vec<M256> = Vec::new();
    for topic in &log.topics {
        topics.push(M256::from_str(&topic).unwrap());
    }
    Log {
        address: Address::from_str(&log.address).unwrap(),
        data: read_hex(&log.data).unwrap(),
        topics: topics,
    }
}

/// Accounts in this list should always be considered exists.
fn irregular_addresses(number: usize) -> HashSet<Address> {
    let config: HashMap<Address, usize> = {
        let mut config = HashMap::new();
        config.insert(Address::from_str("0x0000000000000000000000000000000000000000").unwrap(), 0);
        config.insert(Address::from_str("0x0000000000000000000000000000000000000001").unwrap(), 0);
        config.insert(Address::from_str("0x0000000000000000000000000000000000000002").unwrap(), 505137);
        config.insert(Address::from_str("0x0000000000000000000000000000000000000003").unwrap(), 0);
        config.insert(Address::from_str("0x0000000000000000000000000000000000000004").unwrap(), 0);

        config.insert(Address::from_str("0xbfe465e7eb5a2928b5bf22bef93ad06089dc6179").unwrap(), 229894);
        config.insert(Address::from_str("0xc7585b4ea1829ef37f2fcc6ceaa6063700000000").unwrap(), 188235);
        config.insert(Address::from_str("0x4fea5cb278edfabcc24f7c1425951a0d2faa609b").unwrap(), 370489);

        config
    };

    let mut result: HashSet<Address> = HashSet::new();
    for (key, value) in config {
        if number > value {
            result.insert(key);
        }
    }
    result
}

fn handle_fire(client: &mut GethRPCClient, vm: &mut SeqTransactionVM, last_block_number: &str,
               irregular_addresses: &HashSet<Address>) {
    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 = 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();
                if nonce == M256::zero() && balance == U256::zero() && code.len() == 0 &&
                    !irregular_addresses.contains(&address)
                {
                    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 = M256::from_str(&client.get_block_by_number(&format!("0x{:x}", number))
                                          .hash).unwrap();
                vm.commit_blockhash(number, hash);
            },
        }
    }
}

fn is_miner_or_uncle(address: Address, block: &RPCBlock, client: &mut GethRPCClient) -> 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(client: &mut GethRPCClient, number: usize) {
    let block = client.get_block_by_number(format!("0x{:x}", number).as_str());
    println!("block {}, transaction count: {}", block.number, block.transactions.len());
    let last_number = format!("0x{:x}", number - 1);
    let cur_number = block.number.to_string();
    let block_header = from_rpc_block(&block);
    let irregular_addresses = irregular_addresses(number);

    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(), &FRONTIER_PATCH)
        } else {
            SeqTransactionVM::with_previous(transaction, block_header.clone(), &FRONTIER_PATCH, last_vm.as_ref().unwrap())
        };

        handle_fire(client, &mut vm, &last_number, &irregular_addresses);

        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 {
                &Account::Full {
                    address,
                    balance,
                    ref changing_storage,
                    ..
                } => {
                    if !is_miner_or_uncle(address, &block, client) {
                        let expected_balance = client.get_balance(&format!("0x{:x}", address),
                                                                  &cur_number);
                        assert!(U256::from_str(&expected_balance).unwrap() == 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),
                                                                   &cur_number);
                        assert!(M256::from_str(&expected_value).unwrap() == value);
                    }
                },
                &Account::Create {
                    address,
                    balance,
                    ref storage,
                    ..
                } => {
                    if !is_miner_or_uncle(address, &block, client) {
                        let expected_balance = client.get_balance(&format!("0x{:x}", address),
                                                                  &cur_number);
                        assert!(U256::from_str(&expected_balance).unwrap() == balance);
                    }
                    let storage: HashMap<M256, 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);
                    }
                },
                &Account::IncreaseBalance(address, balance) => {
                    if !is_miner_or_uncle(address, &block, client) {
                        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());
                    }
                },
                &Account::DecreaseBalance(address, balance) => {
                    if !is_miner_or_uncle(address, &block, client) {
                        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 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`.")
    ).get_matches();

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

    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(&mut client, n);
        }
    } else {
        let number = usize::from_str_radix(&number, 10).unwrap();
        test_block(&mut client, number);
    }
}
<|endoftext|>


<commit_before>extern crate mpi;

use mpi::traits::*;

fn main() {
    let universe = mpi::initialize().unwrap();
    let world = universe.world();

    let x = 3.1415f32;
    let mut y: f32 = 0.0;

    {
        let sreq = world.this_process().immediate_send(&x);
        let rreq = world.immediate_receive_into(&mut y);
        rreq.wait();
        sreq.wait();
    }

    assert_eq!(x, y);
}
<commit_msg>Include Test in immediate example.<commit_after>extern crate mpi;

use mpi::traits::*;

fn main() {
    let universe = mpi::initialize().unwrap();
    let world = universe.world();

    let x = 3.1415f32;
    let mut y: f32 = 0.0;

    {
        let mut sreq = world.this_process().immediate_send(&x);
        let rreq = world.immediate_receive_into(&mut y);
        rreq.wait();
        loop {
            match sreq.test() {
                Ok(_) => { break; }
                Err(req) => { sreq = req; }
            }
        }
    }

    assert_eq!(x, y);
}
<|endoftext|>


<commit_before>#![allow(dead_code)]
extern crate mio;

use self::mio::tcp::TcpStream;
use self::mio::{Token, Poll, Ready, PollOpt};
use std::io::ErrorKind;
use std::io::Read;

/// Structure for handling TCP connection functionality
pub struct TcpReaderConn {
    // api version for this connection
    pub api_version: u32,
    // TCP stream socket handle
    pub socket: TcpStream,
    // token for event loop
    pub socket_token: Token,
    // unique prime value
    pub value: u64,

    // values for keeping pending data information
    pending_length: usize,
    pending_index: usize,
    pending_data: Vec<Vec<u8>>,
    // for getting number out of bytes we need to read
    // 4 bytes as a u32 (unsigned int32)
    // so we need to keep indexes for that 4 bytes
    endian_bytes: Vec<u8>,
    endian_bytes_index: usize
}

pub struct TcpWriterConn {
    // TCP stream socket handle
    socket: TcpStream,
    // token for event loop
    socket_token: Token,
    // unique prime value
    value: u64,

    // values for keeping write queue
    write_queue: Vec<Vec<u8>>,
    write_queue_element_index: usize,
}

impl TcpReaderConn {
    pub fn new(socket: TcpStream, token: Token) -> TcpReaderConn {
        TcpReaderConn {
            api_version: 0,
            socket: socket,
            socket_token: token,
            value: 0,
            pending_length: 0,
            pending_index: 0,
            pending_data: vec![],
            endian_bytes: vec![0; 4],
            endian_bytes_index: 0
        }
    }

    #[inline(always)]
    fn read_big_endian(&mut self) -> (bool, Option<u32>) {
        let read_len = match self.socket.read(&mut self.endian_bytes) {
            Ok(n) => n,
            Err(e) => {
                // if we got WouldBlock, then this is Non Blocking socket
                // and data still not available for this, so it's not a connection error
                if e.kind() == ErrorKind::WouldBlock {
                    return (false, Some(0));
                }

                return (true, None);
            }
        };

        if read_len < 4 {

        }

        (false, None)
    }

    /// Registering TCP connection to given POLL event loop
    #[inline(always)]
    pub fn register(&self, poll: &Poll) -> bool {
        match poll.register(&self.socket, self.socket_token, Ready::readable(), PollOpt::edge()) {
            Ok(_) => true,
            Err(e) => {
                warn!("Unable to register connection to Poll service ! -> {}", e);
                false
            }
        }
    }

    /// Reading API version from TCP socket
    /// Function will return 'None' if there is a
    /// problem with connection and it need to be closed
    #[inline(always)]
    pub fn read_api_version(&mut self) -> Option<bool> {
        let (done, version) = self.read_big_endian();
        if !done {
            return Some(false);
        }

        if version.is_none() {
            return None;
        }

        self.api_version = version.unwrap();

        Some(true)
    }
}
<commit_msg>reading big endian number<commit_after>#![allow(dead_code)]
extern crate mio;

use self::mio::tcp::TcpStream;
use self::mio::{Token, Poll, Ready, PollOpt};
use std::io::ErrorKind;
use std::io::Read;
use std::mem;

/// Structure for handling TCP connection functionality
pub struct TcpReaderConn {
    // api version for this connection
    pub api_version: u32,
    // TCP stream socket handle
    pub socket: TcpStream,
    // token for event loop
    pub socket_token: Token,
    // unique prime value
    pub value: u64,

    // values for keeping pending data information
    pending_length: usize,
    pending_index: usize,
    pending_data: Vec<Vec<u8>>,
    // for getting number out of bytes we need to read
    // 4 bytes as a u32 (unsigned int32)
    // so we need to keep indexes for that 4 bytes
    endian_bytes: Vec<u8>,
    endian_bytes_index: usize
}

pub struct TcpWriterConn {
    // TCP stream socket handle
    socket: TcpStream,
    // token for event loop
    socket_token: Token,
    // unique prime value
    value: u64,

    // values for keeping write queue
    write_queue: Vec<Vec<u8>>,
    write_queue_element_index: usize,
}

impl TcpReaderConn {
    pub fn new(socket: TcpStream, token: Token) -> TcpReaderConn {
        TcpReaderConn {
            api_version: 0,
            socket: socket,
            socket_token: token,
            value: 0,
            pending_length: 0,
            pending_index: 0,
            pending_data: vec![],
            endian_bytes: vec![0; 4],
            endian_bytes_index: 0
        }
    }

    #[inline(always)]
    fn read_big_endian(&mut self) -> (bool, Option<u32>) {
        let read_len = match self.socket.read(&mut self.endian_bytes[self.endian_bytes_index..]) {
            Ok(n) => n,
            Err(e) => {
                // if we got WouldBlock, then this is Non Blocking socket
                // and data still not available for this, so it's not a connection error
                if e.kind() == ErrorKind::WouldBlock {
                    return (false, Some(0));
                }

                return (true, None);
            }
        };

        self.endian_bytes_index += read_len;
        // if we still have some data to read
        if self.endian_bytes_index < self.endian_bytes_index {
            return (false, Some(0));
        }

        // if we got here then just setting BigEndian bytes and returning parsed number
        (true, Some(unsafe {
            let a = [self.endian_bytes[0]
                      , self.endian_bytes[1]
                      , self.endian_bytes[2]
                      , self.endian_bytes[3]];
            let endian_num = mem::transmute::<[u8; 4], u32>(a);
            u32::from_be(endian_num)
        }))
    }

    /// Registering TCP connection to given POLL event loop
    #[inline(always)]
    pub fn register(&self, poll: &Poll) -> bool {
        match poll.register(&self.socket, self.socket_token, Ready::readable(), PollOpt::edge()) {
            Ok(_) => true,
            Err(e) => {
                warn!("Unable to register connection to Poll service ! -> {}", e);
                false
            }
        }
    }

    /// Reading API version from TCP socket
    /// Function will return 'None' if there is a
    /// problem with connection and it need to be closed
    #[inline(always)]
    pub fn read_api_version(&mut self) -> Option<bool> {
        let (done, version) = self.read_big_endian();
        if !done {
            return Some(false);
        }

        if version.is_none() {
            return None;
        }

        self.api_version = version.unwrap();

        Some(true)
    }
}
<|endoftext|>


<commit_before>// Copyright 2017 The Exonum Team
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//   http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

//! `RESTful` API and corresponding utilities.

use std::ops::Deref;
use std::marker::PhantomData;
use std::io;
use std::collections::BTreeMap;
use std::fmt;
use std::str::FromStr;

use iron::IronError;
use iron::prelude::*;
use iron::status;
use iron::headers::Cookie;
use hyper::header::{ContentType, SetCookie};
use cookie::Cookie as CookiePair;
use router::Router;
use params;
use serde_json;
use serde::{Serialize, Serializer};
use serde::de::{self, Visitor, Deserialize, Deserializer};
use failure::Fail;

use crypto::{PublicKey, SecretKey};
use encoding::serialize::{FromHex, FromHexError, ToHex, encode_hex};
use storage;

pub mod public;
pub mod private;
#[cfg(test)]
mod tests;

/// List of possible Api errors.
#[derive(Fail, Debug)]
pub enum ApiError {
    /// Storage error.
    #[fail(display = "Storage error: {}", _0)]
    Storage(
        #[cause]
        storage::Error
    ),

    /// Input/output error.
    #[fail(display = "IO error: {}", _0)]
    Io(
        #[cause]
        ::std::io::Error
    ),

    /// Bad request.
    #[fail(display = "Bad request: {}", _0)]
    BadRequest(String),

    /// Internal error.
    #[fail(display = "Internal server error: {}", _0)]
    InternalError(Box<::std::error::Error + Send + Sync>),

    /// Unauthorized error.
    #[fail(display = "Unauthorized")]
    Unauthorized,
}

impl From<io::Error> for ApiError {
    fn from(e: io::Error) -> ApiError {
        ApiError::Io(e)
    }
}

impl From<storage::Error> for ApiError {
    fn from(e: storage::Error) -> ApiError {
        ApiError::Storage(e)
    }
}

impl From<ApiError> for IronError {
    fn from(e: ApiError) -> IronError {
        let code = match e {
            // Note that `status::Unauthorized` does not fit here, because
            //
            // > A server generating a 401 (Unauthorized) response MUST send a
            // > WWW-Authenticate header field containing at least one challenge.
            //
            // https://tools.ietf.org/html/rfc7235#section-4.1
            ApiError::Unauthorized => status::Forbidden,

            ApiError::BadRequest(..) => status::BadRequest,

            ApiError::Storage(..) |
            ApiError::Io(..) |
            ApiError::InternalError(..) => status::InternalServerError,
        };
        let body = {
            let mut map = BTreeMap::new();
            map.insert("debug", format!("{:?}", e));
            map.insert("description", e.to_string());
            ::serde_json::to_string_pretty(&map).unwrap()
        };
        IronError::new(e.compat(), (code, body))
    }
}

/// `Field` that is serialized/deserialized from/to hex.
#[derive(Clone, Debug)]
struct HexField<T: AsRef<[u8]> + Clone>(pub T);

impl<T> Deref for HexField<T>
where
    T: AsRef<[u8]> + Clone,
{
    type Target = T;

    fn deref(&self) -> &T {
        &self.0
    }
}

impl<T> Serialize for HexField<T>
where
    T: AsRef<[u8]> + Clone,
{
    fn serialize<S>(&self, ser: S) -> Result<S::Ok, S::Error>
    where
        S: Serializer,
    {
        ser.serialize_str(&encode_hex(&self.0))
    }
}

struct HexVisitor<T>
where
    T: AsRef<[u8]> + Clone + FromHex<Error = FromHexError>,
{
    _p: PhantomData<T>,
}

impl<'v, T> Visitor<'v> for HexVisitor<T>
where
    T: AsRef<[u8]> + Clone + FromHex<Error = FromHexError>,
{
    type Value = HexField<T>;

    fn expecting(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        write!(fmt, "expected hex represented string")
    }

    fn visit_str<E>(self, s: &str) -> Result<HexField<T>, E>
    where
        E: de::Error,
    {
        let v = T::from_hex(s).map_err(|_| de::Error::custom("Invalid hex"))?;
        Ok(HexField(v))
    }
}

impl<'de, T> Deserialize<'de> for HexField<T>
where
    T: AsRef<[u8]>
        + FromHex<Error = FromHexError>
        + ToHex
        + Clone,
{
    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
    where
        D: Deserializer<'de>,
    {
        deserializer.deserialize_str(HexVisitor { _p: PhantomData })
    }
}

/// `Api` trait defines `RESTful` API.
pub trait Api {
    /// Loads hex value from the cookies.
    fn load_hex_value_from_cookie<'a>(
        &self,
        request: &'a Request,
        key: &str,
    ) -> storage::Result<Vec<u8>> {
        if let Some(&Cookie(ref cookies)) = request.headers.get() {
            for cookie in cookies.iter() {
                if let Ok(c) = CookiePair::parse(cookie.as_str()) {
                    if c.name() == key {
                        if let Ok(value) = FromHex::from_hex(c.value()) {
                            return Ok(value);
                        }
                    }
                }
            }
        }
        Err(storage::Error::new(
            format!("Unable to find value with given key {}", key),
        ))
    }

    /// Loads public and secret key from the cookies.
    fn load_keypair_from_cookies(
        &self,
        request: &Request,
    ) -> Result<(PublicKey, SecretKey), ApiError> {
        let public_key = PublicKey::from_slice(
            self.load_hex_value_from_cookie(request, "public_key")?
                .as_ref(),
        );
        let secret_key = SecretKey::from_slice(
            self.load_hex_value_from_cookie(request, "secret_key")?
                .as_ref(),
        );

        let public_key = public_key.ok_or(ApiError::Unauthorized)?;
        let secret_key = secret_key.ok_or(ApiError::Unauthorized)?;
        Ok((public_key, secret_key))
    }

    //TODO: Remove duplicate code
    /// Returns NotFound and some response with cookies.
    fn not_found_response_with_cookies(
        &self,
        json: &serde_json::Value,
        cookies: Option<Vec<String>>,
    ) -> IronResult<Response> {
        let mut resp = Response::with((
            status::NotFound,
            serde_json::to_string_pretty(json).unwrap(),
        ));
        resp.headers.set(ContentType::json());
        if let Some(cookies) = cookies {
            resp.headers.set(SetCookie(cookies));
        }
        Ok(resp)
    }

    /// Returns OK and some response with cookies.
    fn ok_response_with_cookies(
        &self,
        json: &serde_json::Value,
        cookies: Option<Vec<String>>,
    ) -> IronResult<Response> {
        let mut resp = Response::with((status::Ok, serde_json::to_string_pretty(json).unwrap()));
        resp.headers.set(ContentType::json());
        if let Some(cookies) = cookies {
            resp.headers.set(SetCookie(cookies));
        }
        Ok(resp)
    }

    /// Returns OK and some response.
    fn ok_response(&self, json: &serde_json::Value) -> IronResult<Response> {
        self.ok_response_with_cookies(json, None)
    }
    /// Returns NotFound and some response.
    fn not_found_response(&self, json: &serde_json::Value) -> IronResult<Response> {
        self.not_found_response_with_cookies(json, None)
    }

    /// Used to extend Api.
    fn wire<'b>(&self, router: &'b mut Router);
}

fn url_fragment<T>(request: &Request, name: &str) -> Result<T, ApiError>
where
    T: FromStr,
    T::Err: fmt::Display,
{
    let params = request.extensions.get::<Router>().unwrap();
    let fragment = params.find(name).ok_or_else(|| {
        ApiError::BadRequest(format!("Required parameter '{}' is missing", name))
    })?;
    let value: T = T::from_str(fragment).map_err(|e| {
        ApiError::BadRequest(format!("Invalid '{}' parameter: {}", name, e))
    })?;
    Ok(value)
}

fn optional_param<T>(request: &mut Request, name: &str) -> Result<Option<T>, ApiError>
where
    T: FromStr,
    T::Err: fmt::Display,
{
    let map = request.get_ref::<params::Params>().unwrap();
    let value = match map.find(&[name]) {
        Some(&params::Value::String(ref param)) => {
            let value: T = T::from_str(param).map_err(|e| {
                ApiError::BadRequest(format!("Invalid '{}' parameter: {}", name, e))
            })?;
            Some(value)
        }
        _ => None,
    };
    Ok(value)
}

fn required_param<T>(request: &mut Request, name: &str) -> Result<T, ApiError>
where
    T: FromStr,
    T::Err: fmt::Display,
{
    optional_param(request, name)?.ok_or_else(|| {
        ApiError::BadRequest(format!("Required parameter '{}' is missing", name))
    })
}
<commit_msg>Remove unnesseccary type ascription<commit_after>// Copyright 2017 The Exonum Team
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//   http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

//! `RESTful` API and corresponding utilities.

use std::ops::Deref;
use std::marker::PhantomData;
use std::io;
use std::collections::BTreeMap;
use std::fmt;
use std::str::FromStr;

use iron::IronError;
use iron::prelude::*;
use iron::status;
use iron::headers::Cookie;
use hyper::header::{ContentType, SetCookie};
use cookie::Cookie as CookiePair;
use router::Router;
use params;
use serde_json;
use serde::{Serialize, Serializer};
use serde::de::{self, Visitor, Deserialize, Deserializer};
use failure::Fail;

use crypto::{PublicKey, SecretKey};
use encoding::serialize::{FromHex, FromHexError, ToHex, encode_hex};
use storage;

pub mod public;
pub mod private;
#[cfg(test)]
mod tests;

/// List of possible Api errors.
#[derive(Fail, Debug)]
pub enum ApiError {
    /// Storage error.
    #[fail(display = "Storage error: {}", _0)]
    Storage(
        #[cause]
        storage::Error
    ),

    /// Input/output error.
    #[fail(display = "IO error: {}", _0)]
    Io(
        #[cause]
        ::std::io::Error
    ),

    /// Bad request.
    #[fail(display = "Bad request: {}", _0)]
    BadRequest(String),

    /// Internal error.
    #[fail(display = "Internal server error: {}", _0)]
    InternalError(Box<::std::error::Error + Send + Sync>),

    /// Unauthorized error.
    #[fail(display = "Unauthorized")]
    Unauthorized,
}

impl From<io::Error> for ApiError {
    fn from(e: io::Error) -> ApiError {
        ApiError::Io(e)
    }
}

impl From<storage::Error> for ApiError {
    fn from(e: storage::Error) -> ApiError {
        ApiError::Storage(e)
    }
}

impl From<ApiError> for IronError {
    fn from(e: ApiError) -> IronError {
        let code = match e {
            // Note that `status::Unauthorized` does not fit here, because
            //
            // > A server generating a 401 (Unauthorized) response MUST send a
            // > WWW-Authenticate header field containing at least one challenge.
            //
            // https://tools.ietf.org/html/rfc7235#section-4.1
            ApiError::Unauthorized => status::Forbidden,

            ApiError::BadRequest(..) => status::BadRequest,

            ApiError::Storage(..) |
            ApiError::Io(..) |
            ApiError::InternalError(..) => status::InternalServerError,
        };
        let body = {
            let mut map = BTreeMap::new();
            map.insert("debug", format!("{:?}", e));
            map.insert("description", e.to_string());
            ::serde_json::to_string_pretty(&map).unwrap()
        };
        IronError::new(e.compat(), (code, body))
    }
}

/// `Field` that is serialized/deserialized from/to hex.
#[derive(Clone, Debug)]
struct HexField<T: AsRef<[u8]> + Clone>(pub T);

impl<T> Deref for HexField<T>
where
    T: AsRef<[u8]> + Clone,
{
    type Target = T;

    fn deref(&self) -> &T {
        &self.0
    }
}

impl<T> Serialize for HexField<T>
where
    T: AsRef<[u8]> + Clone,
{
    fn serialize<S>(&self, ser: S) -> Result<S::Ok, S::Error>
    where
        S: Serializer,
    {
        ser.serialize_str(&encode_hex(&self.0))
    }
}

struct HexVisitor<T>
where
    T: AsRef<[u8]> + Clone + FromHex<Error = FromHexError>,
{
    _p: PhantomData<T>,
}

impl<'v, T> Visitor<'v> for HexVisitor<T>
where
    T: AsRef<[u8]> + Clone + FromHex<Error = FromHexError>,
{
    type Value = HexField<T>;

    fn expecting(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        write!(fmt, "expected hex represented string")
    }

    fn visit_str<E>(self, s: &str) -> Result<HexField<T>, E>
    where
        E: de::Error,
    {
        let v = T::from_hex(s).map_err(|_| de::Error::custom("Invalid hex"))?;
        Ok(HexField(v))
    }
}

impl<'de, T> Deserialize<'de> for HexField<T>
where
    T: AsRef<[u8]>
        + FromHex<Error = FromHexError>
        + ToHex
        + Clone,
{
    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
    where
        D: Deserializer<'de>,
    {
        deserializer.deserialize_str(HexVisitor { _p: PhantomData })
    }
}

/// `Api` trait defines `RESTful` API.
pub trait Api {
    /// Loads hex value from the cookies.
    fn load_hex_value_from_cookie<'a>(
        &self,
        request: &'a Request,
        key: &str,
    ) -> storage::Result<Vec<u8>> {
        if let Some(&Cookie(ref cookies)) = request.headers.get() {
            for cookie in cookies.iter() {
                if let Ok(c) = CookiePair::parse(cookie.as_str()) {
                    if c.name() == key {
                        if let Ok(value) = FromHex::from_hex(c.value()) {
                            return Ok(value);
                        }
                    }
                }
            }
        }
        Err(storage::Error::new(
            format!("Unable to find value with given key {}", key),
        ))
    }

    /// Loads public and secret key from the cookies.
    fn load_keypair_from_cookies(
        &self,
        request: &Request,
    ) -> Result<(PublicKey, SecretKey), ApiError> {
        let public_key = PublicKey::from_slice(
            self.load_hex_value_from_cookie(request, "public_key")?
                .as_ref(),
        );
        let secret_key = SecretKey::from_slice(
            self.load_hex_value_from_cookie(request, "secret_key")?
                .as_ref(),
        );

        let public_key = public_key.ok_or(ApiError::Unauthorized)?;
        let secret_key = secret_key.ok_or(ApiError::Unauthorized)?;
        Ok((public_key, secret_key))
    }

    //TODO: Remove duplicate code
    /// Returns NotFound and some response with cookies.
    fn not_found_response_with_cookies(
        &self,
        json: &serde_json::Value,
        cookies: Option<Vec<String>>,
    ) -> IronResult<Response> {
        let mut resp = Response::with((
            status::NotFound,
            serde_json::to_string_pretty(json).unwrap(),
        ));
        resp.headers.set(ContentType::json());
        if let Some(cookies) = cookies {
            resp.headers.set(SetCookie(cookies));
        }
        Ok(resp)
    }

    /// Returns OK and some response with cookies.
    fn ok_response_with_cookies(
        &self,
        json: &serde_json::Value,
        cookies: Option<Vec<String>>,
    ) -> IronResult<Response> {
        let mut resp = Response::with((status::Ok, serde_json::to_string_pretty(json).unwrap()));
        resp.headers.set(ContentType::json());
        if let Some(cookies) = cookies {
            resp.headers.set(SetCookie(cookies));
        }
        Ok(resp)
    }

    /// Returns OK and some response.
    fn ok_response(&self, json: &serde_json::Value) -> IronResult<Response> {
        self.ok_response_with_cookies(json, None)
    }
    /// Returns NotFound and some response.
    fn not_found_response(&self, json: &serde_json::Value) -> IronResult<Response> {
        self.not_found_response_with_cookies(json, None)
    }

    /// Used to extend Api.
    fn wire<'b>(&self, router: &'b mut Router);
}

fn url_fragment<T>(request: &Request, name: &str) -> Result<T, ApiError>
where
    T: FromStr,
    T::Err: fmt::Display,
{
    let params = request.extensions.get::<Router>().unwrap();
    let fragment = params.find(name).ok_or_else(|| {
        ApiError::BadRequest(format!("Required parameter '{}' is missing", name))
    })?;
    let value = T::from_str(fragment).map_err(|e| {
        ApiError::BadRequest(format!("Invalid '{}' parameter: {}", name, e))
    })?;
    Ok(value)
}

fn optional_param<T>(request: &mut Request, name: &str) -> Result<Option<T>, ApiError>
where
    T: FromStr,
    T::Err: fmt::Display,
{
    let map = request.get_ref::<params::Params>().unwrap();
    let value = match map.find(&[name]) {
        Some(&params::Value::String(ref param)) => {
            let value = T::from_str(param).map_err(|e| {
                ApiError::BadRequest(format!("Invalid '{}' parameter: {}", name, e))
            })?;
            Some(value)
        }
        _ => None,
    };
    Ok(value)
}

fn required_param<T>(request: &mut Request, name: &str) -> Result<T, ApiError>
where
    T: FromStr,
    T::Err: fmt::Display,
{
    optional_param(request, name)?.ok_or_else(|| {
        ApiError::BadRequest(format!("Required parameter '{}' is missing", name))
    })
}
<|endoftext|>


<commit_before>// Options
// Space before /
// Quote style
// Ordering of attributes

#[cfg(test)]
mod test {
    use std::io::{IoResult,MemWriter};

    use super::super::{Document,Element};
    use super::super::{ElementElementChild,TextElementChild,CommentElementChild,PIElementChild};

    macro_rules! assert_str_eq(
        ($l:expr, $r:expr) => (assert_eq!($l.as_slice(), $r.as_slice()));
    )

    enum Content {
        WElement(Element),
        WElementEnd(String),
    }

    fn format_element<W : Writer>(element: Element, todo: &mut Vec<Content>, writer: &mut W) -> IoResult<()> {
        try!(write!(writer, "<{}", element.name()));

        for attr in element.attributes().iter() {
            try!(write!(writer, " {}='{}'", attr.name(), attr.value()));
        }

        let mut children = element.children();
        if children.is_empty() {
            writer.write_str("/>")
        } else {
            try!(writer.write_str(">"));

            todo.push(WElementEnd(element.name()));
            children.reverse();
            let x = children.move_iter().map(|c| match c {
                ElementElementChild(element) => WElement(element),
                TextElementChild(_) => fail!("text?"),
                CommentElementChild(_) => fail!("comment?"),
                PIElementChild(_) => fail!("PI?"),
            }).collect();
            todo.push_all_move(x);

            Ok(())
        }
    }

    fn format_document<W : Writer>(doc: &Document, writer: &mut W) -> IoResult<()> {
        let mut todo = Vec::new();

        try!(writer.write_str("<?xml version='1.0'?>"));
        let e = doc.root().children()[0].element().expect("not an element?");

        todo.push(WElement(e));

        while ! todo.is_empty() {
            match todo.pop().unwrap() {
                WElement(e) => try!(format_element(e, &mut todo, writer)),
                WElementEnd(name) => try!(write!(writer, "</{}>", name)),
            }
        }

        Ok(())
    }

    fn format_xml(doc: &Document) -> String {
        let mut w = MemWriter::new();
        format_document(doc, &mut w).ok().expect("Not formatted");
        String::from_utf8(w.unwrap()).ok().expect("Not a string")
    }

    #[test]
    fn top_element() {
        let d = Document::new();
        let e = d.new_element("hello".to_string());
        d.root().append_child(e);

        let xml = format_xml(&d);
        assert_str_eq!(xml, "<?xml version='1.0'?><hello/>");
    }

    #[test]
    fn element_with_attributes() {
        let d = Document::new();
        let e = d.new_element("hello".to_string());
        e.set_attribute("a".to_string(), "b".to_string());
        d.root().append_child(e);

        let xml = format_xml(&d);
        assert_str_eq!(xml, "<?xml version='1.0'?><hello a='b'/>");
    }

    #[test]
    fn nested_element() {
        let d = Document::new();
        let hello = d.new_element("hello".to_string());
        let world = d.new_element("world".to_string());
        hello.append_child(world);
        d.root().append_child(hello);

        let xml = format_xml(&d);
        assert_str_eq!(xml, "<?xml version='1.0'?><hello><world/></hello>");
    }
}
<commit_msg>Write text nodes<commit_after>// Options
// Space before /
// Quote style
// Ordering of attributes

#[cfg(test)]
mod test {
    use std::io::{IoResult,MemWriter};

    use super::super::{Document,Element,Text};
    use super::super::{ElementElementChild,TextElementChild,CommentElementChild,PIElementChild};

    macro_rules! assert_str_eq(
        ($l:expr, $r:expr) => (assert_eq!($l.as_slice(), $r.as_slice()));
    )

    enum Content {
        WElement(Element),
        WElementEnd(String),
        WText(Text),
    }

    fn format_element<W : Writer>(element: Element, todo: &mut Vec<Content>, writer: &mut W) -> IoResult<()> {
        try!(write!(writer, "<{}", element.name()));

        for attr in element.attributes().iter() {
            try!(write!(writer, " {}='{}'", attr.name(), attr.value()));
        }

        let mut children = element.children();
        if children.is_empty() {
            writer.write_str("/>")
        } else {
            try!(writer.write_str(">"));

            todo.push(WElementEnd(element.name()));
            children.reverse();
            let x = children.move_iter().map(|c| match c {
                ElementElementChild(element) => WElement(element),
                TextElementChild(t) => WText(t),
                CommentElementChild(_) => fail!("comment?"),
                PIElementChild(_) => fail!("PI?"),
            }).collect();
            todo.push_all_move(x);

            Ok(())
        }
    }

    fn format_document<W : Writer>(doc: &Document, writer: &mut W) -> IoResult<()> {
        let mut todo = Vec::new();

        try!(writer.write_str("<?xml version='1.0'?>"));
        let e = doc.root().children()[0].element().expect("not an element?");

        todo.push(WElement(e));

        while ! todo.is_empty() {
            match todo.pop().unwrap() {
                WElement(e) => try!(format_element(e, &mut todo, writer)),
                WElementEnd(name) => try!(write!(writer, "</{}>", name)),
                WText(t) => try!(writer.write_str(t.text().as_slice())),
            }
        }

        Ok(())
    }

    fn format_xml(doc: &Document) -> String {
        let mut w = MemWriter::new();
        format_document(doc, &mut w).ok().expect("Not formatted");
        String::from_utf8(w.unwrap()).ok().expect("Not a string")
    }

    #[test]
    fn top_element() {
        let d = Document::new();
        let e = d.new_element("hello".to_string());
        d.root().append_child(e);

        let xml = format_xml(&d);
        assert_str_eq!(xml, "<?xml version='1.0'?><hello/>");
    }

    #[test]
    fn element_with_attributes() {
        let d = Document::new();
        let e = d.new_element("hello".to_string());
        e.set_attribute("a".to_string(), "b".to_string());
        d.root().append_child(e);

        let xml = format_xml(&d);
        assert_str_eq!(xml, "<?xml version='1.0'?><hello a='b'/>");
    }

    #[test]
    fn nested_element() {
        let d = Document::new();
        let hello = d.new_element("hello".to_string());
        let world = d.new_element("world".to_string());
        hello.append_child(world);
        d.root().append_child(hello);

        let xml = format_xml(&d);
        assert_str_eq!(xml, "<?xml version='1.0'?><hello><world/></hello>");
    }

    #[test]
    fn nested_text() {
        let d = Document::new();
        let hello = d.new_element("hello".to_string());
        let text = d.new_text("A fine day to you!".to_string());
        hello.append_child(text);
        d.root().append_child(hello);

        let xml = format_xml(&d);
        assert_str_eq!(xml, "<?xml version='1.0'?><hello>A fine day to you!</hello>");
    }
}
<|endoftext|>


<commit_before>#![feature(inclusive_range_syntax)]
extern crate rudy;
use rudy::rudymap::RudyMap;

fn main() {
    let mut map = RudyMap::new();
    let low = 0u32;
    let high = 10000u32;
    for i in low..high {
        map.insert(i, i + 1);
    }
    for i in low..high {
        assert_eq!(map.get(i).cloned(), Some(i + 1));
    }
    println!("{}", map.len());
    for i in low..high {
        assert_eq!(map.remove(i), Some(i + 1));
    }
    for i in low..high {
        assert_eq!(map.get(i), None);
    }
    for i in 5...7 {
        println!("{} => {:?}", i, map.get(i));
    }
    println!("{}", map.len());
}
<commit_msg>Remove nightly feature from removal example.<commit_after>extern crate rudy;
use rudy::rudymap::RudyMap;

fn main() {
    let mut map = RudyMap::new();
    let low = 0u32;
    let high = 10000u32;
    for i in low..high {
        map.insert(i, i + 1);
    }
    for i in low..high {
        assert_eq!(map.get(i).cloned(), Some(i + 1));
    }
    println!("{}", map.len());
    for i in low..high {
        assert_eq!(map.remove(i), Some(i + 1));
    }
    for i in low..high {
        assert_eq!(map.get(i), None);
    }
    for i in 5..7 {
        println!("{} => {:?}", i, map.get(i));
    }
    println!("{}", map.len());
}
<|endoftext|>


<commit_before>use std::f64::consts::PI;

use turtle::Turtle;

fn main() {
    let mut turtle = Turtle::new();

    turtle.pen_up();
    turtle.backward(250.0);
    turtle.left(90.0);
    turtle.pen_down();

    for &radius in [120.0, 80.0, 60.0].into_iter() {
        circle(&mut turtle, radius);

        turtle.pen_up();
        turtle.right(90.0);
        turtle.forward(radius * 2.0);
        turtle.left(90.0);
        turtle.pen_down();
    }

    turtle.hide();
}

fn circle(turtle: &mut Turtle, radius: f64) {
    let degrees = 180.0;

    let circumference = 2.0 * PI * radius;
    let step = circumference / degrees;
    let rotation = 360.0 / degrees;

    for _ in 0..degrees as i32 {
        turtle.forward(step);
        turtle.right(rotation);
    }
}
<commit_msg>Changed into_iter -> iter to fix warning<commit_after>use std::f64::consts::PI;

use turtle::Turtle;

fn main() {
    let mut turtle = Turtle::new();

    turtle.pen_up();
    turtle.backward(250.0);
    turtle.left(90.0);
    turtle.pen_down();

    for &radius in [120.0, 80.0, 60.0].iter() {
        circle(&mut turtle, radius);

        turtle.pen_up();
        turtle.right(90.0);
        turtle.forward(radius * 2.0);
        turtle.left(90.0);
        turtle.pen_down();
    }

    turtle.hide();
}

fn circle(turtle: &mut Turtle, radius: f64) {
    let degrees = 180.0;

    let circumference = 2.0 * PI * radius;
    let step = circumference / degrees;
    let rotation = 360.0 / degrees;

    for _ in 0..degrees as i32 {
        turtle.forward(step);
        turtle.right(rotation);
    }
}
<|endoftext|>


<commit_before>//! Working with the search list.

use ::bits::{DNameBuf, DNameSlice};
use super::super::Resolver;

//------------ SearchIter ----------------------------------------------------

/// An iterator gained from applying a search list to a domain name.
///
/// The iterator represents how a resolver attempts to derive an absolute
/// domain name from a relative name.
///
/// For this purpose, the resolver’s configuration contains a search list,
/// a list of absolute domain names that are appened in turn to the domain
/// name. In addition, if the name contains enough dots (specifically,
/// `ResolvConf::ndots` which defaults to just one) it is first tried as if
/// it were an absolute by appending the root labels.
pub struct SearchIter {
    /// The base name to work with.
    name: DNameBuf,

    /// The resolver to use for looking up the search list.
    resolv: Resolver,

    /// The state of working through the search list.
    state: SearchState,
}

enum SearchState {
    /// The next value is to be the name treated as an absolute name.
    Absolute,

    /// The next value is to be item with the contained value as index in
    /// the resolver’s search list.
    Search(usize),

    /// All options are exhausted.
    Done,
}

impl SearchIter {
    /// Creates a new search iterator.
    ///
    /// The iterator will yield absolute domain names for `name` based on
    /// the configuration of the given resolver.
    pub fn new(resolv: Resolver, name: &DNameSlice) -> Option<Self> {
        let state = match name.ndots() {
            None => {
                // The name is absolute, no searching is necessary.
                return None
            }
            Some(n) if n >= resolv.conf().ndots => {
                // We have the required amount of dots to start with treating
                // the name as an absolute.
                SearchState::Absolute
            }
            _ => {
                // We don’t have enough dots. Start with the search list
                // right away.
                SearchState::Search(0)
            }
        };
        Some(SearchIter {
            name: name.to_owned(),
            resolv: resolv,
            state: state
        })
    }
}

impl Iterator for SearchIter {
    type Item = DNameBuf;

    fn next(&mut self) -> Option<Self::Item> {
        // The loop is here to quietly skip over all names where joining
        // fails.
        #[allow(never_loop)]
        loop {
            let (res, state) = match self.state {
                SearchState::Absolute => {
                    match self.name.join(&DNameSlice::root()) {
                        Ok(name) => (Some(name), SearchState::Search(0)),
                        Err(_) => continue,
                    }
                }
                SearchState::Search(pos) => {
                    if pos >= self.resolv.conf().search.len() {
                        (None, SearchState::Done)
                    }
                    else {
                        match self.name.join(&self.resolv.conf()
                                                         .search[pos]) {
                            Ok(name) => {
                                (Some(name), SearchState::Search(pos + 1))
                            }
                            Err(_) => continue,
                        }
                    }
                }
                SearchState::Done => return None
            };
            self.state = state;
            return res
        }
    }
}

<commit_msg>Explain the #[allow(...)].<commit_after>//! Working with the search list.

use ::bits::{DNameBuf, DNameSlice};
use super::super::Resolver;

//------------ SearchIter ----------------------------------------------------

/// An iterator gained from applying a search list to a domain name.
///
/// The iterator represents how a resolver attempts to derive an absolute
/// domain name from a relative name.
///
/// For this purpose, the resolver’s configuration contains a search list,
/// a list of absolute domain names that are appened in turn to the domain
/// name. In addition, if the name contains enough dots (specifically,
/// `ResolvConf::ndots` which defaults to just one) it is first tried as if
/// it were an absolute by appending the root labels.
pub struct SearchIter {
    /// The base name to work with.
    name: DNameBuf,

    /// The resolver to use for looking up the search list.
    resolv: Resolver,

    /// The state of working through the search list.
    state: SearchState,
}

enum SearchState {
    /// The next value is to be the name treated as an absolute name.
    Absolute,

    /// The next value is to be item with the contained value as index in
    /// the resolver’s search list.
    Search(usize),

    /// All options are exhausted.
    Done,
}

impl SearchIter {
    /// Creates a new search iterator.
    ///
    /// The iterator will yield absolute domain names for `name` based on
    /// the configuration of the given resolver.
    pub fn new(resolv: Resolver, name: &DNameSlice) -> Option<Self> {
        let state = match name.ndots() {
            None => {
                // The name is absolute, no searching is necessary.
                return None
            }
            Some(n) if n >= resolv.conf().ndots => {
                // We have the required amount of dots to start with treating
                // the name as an absolute.
                SearchState::Absolute
            }
            _ => {
                // We don’t have enough dots. Start with the search list
                // right away.
                SearchState::Search(0)
            }
        };
        Some(SearchIter {
            name: name.to_owned(),
            resolv: resolv,
            state: state
        })
    }
}

impl Iterator for SearchIter {
    type Item = DNameBuf;

    fn next(&mut self) -> Option<Self::Item> {
        // The loop is here to quietly skip over all names where joining
        // fails.
        #[allow(never_loop)] // False positive by Clippy. It totally does loop
        loop {
            let (res, state) = match self.state {
                SearchState::Absolute => {
                    match self.name.join(&DNameSlice::root()) {
                        Ok(name) => (Some(name), SearchState::Search(0)),
                        Err(_) => continue,
                    }
                }
                SearchState::Search(pos) => {
                    if pos >= self.resolv.conf().search.len() {
                        (None, SearchState::Done)
                    }
                    else {
                        match self.name.join(&self.resolv.conf()
                                                         .search[pos]) {
                            Ok(name) => {
                                (Some(name), SearchState::Search(pos + 1))
                            }
                            Err(_) => continue,
                        }
                    }
                }
                SearchState::Done => return None
            };
            self.state = state;
            return res
        }
    }
}

<|endoftext|>