<commit_before>//
// MSX CAS Packager
// Copyright (c) 2015 Alvaro Polo
//
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.

extern crate byteorder;
extern crate docopt;
extern crate rustc_serialize;

#[cfg(test)]
extern crate quickcheck;

mod args;
mod tape;
mod wav;

use std::fs;
use std::fs::File;
use std::io::Read;
use std::io::Write;

#[allow(dead_code)]
fn main() {
    let cmd = args::parse();
    match cmd {
        args::Command::Version => print_version(),
        args::Command::List(path) => list_files(&path[..]),
        args::Command::Add(path, files) =>  add_files(&path[..], &files[..]),
        args::Command::Extract(path) => extract_all(&path[..]),
        args::Command::Export(_, _) => {},
    };
}

fn print_version() {
    println!("MSX CAS Packager (MCP) v0.1.0");
    println!("Copyright (C) 2015 Alvaro Polo");
    println!("");
    println!("This program is subject to the terms of the Mozilla Public License v2.0.");
    println!("");
}

macro_rules! open_file {
    ($path: expr) => ({
        match File::open($path) {
            Ok(f) => f,
            Err(e) => {
                println!("Cannot open file '{}': {}", $path, e);
                return
            }
        }
    })
}

macro_rules! create_file {
    ($path: expr) => ({
        match File::create($path) {
            Ok(f) => f,
            Err(e) => {
                println!("Cannot create file '{}': {}", $path, e);
                return
            }
        }
    })
}

macro_rules! read_file {
    ($name: expr, $file: expr, $data: expr) => ({
        match $file.read_to_end($data) {
            Ok(_) => {},
            Err(e) => {
                println!("Cannot read from file '{}': {}", $name, e);
            },
        };
    });
    ($name: expr) => ({
        let file = open_file!($name);
        let mut data: Vec<u8> = vec![];
        read_file!($name, &file, &mut data);
        data
    });
}

macro_rules! write_file {
    ($name: expr, $file: expr, $data: expr) => ({
        match $file.write_all($data) {
            Ok(_) => {},
            Err(e) => {
                println!("Cannot write to file '{}': {}", $name, e);
            },
        };
    })
}

macro_rules! open_tape {
    ($path: expr) => ({
        let mut tape_file = open_file!($path);
        match tape::Tape::read(&mut tape_file) {
            Ok(f) => f,
            Err(e) => {
                println!("Cannot read file '{}': {}", $path, e);
                return
            }
        }
    })
}

macro_rules! open_or_create_tape {
    ($path: expr) => ({
        match File::open($path) {
            Ok(mut f) => {
                match tape::Tape::read(&mut f) {
                    Ok(f) => (f, true),
                    Err(e) => {
                        println!("Cannot read file '{}': {}", $path, e);
                        return
                    }
                }
            },
            Err(_) => (tape::Tape::new(), false),
        }
    })
}

macro_rules! file_name {
    ($file: expr) => ({
        let fname = &$file[..$file.len() - 4];
        if fname.len() > 6 {
            println!("Warning: filename {} is too long, truncating", $file);
        }
        tape::file_name(fname)
    })
}

fn list_files(path: &str) {
    let tape = open_tape!(path);
    for file in tape.files() {
        match file {
            tape::File::Bin(name, begin, end, start, data) => {
                println!("bin    | {:6} | {:5} bytes | [0x{:x},0x{:x}]:0x{:x}",
                    name, data.len(), begin, end, start);
            },
            tape::File::Basic(name, data) => {
                println!("basic  | {:6} | {:5} bytes |", name, data.len());
            },
            tape::File::Ascii(name, data) => {
                let nbytes = data.iter().fold(0, |size, chunk| size + chunk.len());
                println!("ascii  | {:6} | {:5} bytes |", name, nbytes);
            },
            tape::File::Custom(data) => {
                println!("custom |        | {:5} bytes |", data.len());
            }
        };
    }
}

fn extract_all(path: &str) {
    let tape = open_tape!(path);
    let mut next_custom = 0;
    for file in tape.files() {
        let out_path = file.name()
            .map(|n| n.to_string())
            .unwrap_or_else(|| format!("custom.{:03}", { next_custom += 1; next_custom }));
        print!("Extracting {}... ", out_path);
        extract_file(&file, &out_path[..]);
        println!("Done");
    }
}

fn extract_file(file: &tape::File, out_path: &str) {
    let mut ofile = create_file!(out_path);
    match file {
        &tape::File::Bin(_, _, _, _, data) => {
            write_file!(out_path, ofile, data);
        },
        &tape::File::Basic(_, data) => {
            write_file!(out_path, ofile, data);
        },
        &tape::File::Ascii(_, ref chunks) => {
            for chunk in chunks {
                let last = chunk.iter().position(|b| *b == 0x1a).unwrap_or(chunk.len());
                write_file!(out_path, ofile, &chunk[..last]);
            }
        },
        &tape::File::Custom(ref data) => {
            write_file!(out_path, ofile, data);
        },
    }
}

fn add_files(path: &str, files: &[String]) {
    let (mut tape, tape_exist) = open_or_create_tape!(path);
    for fname in files {
        print!("Adding {}... ", fname);
        if fname.ends_with(".bin") {
            add_bin_file(&mut tape, &fname[..]);
        } else if fname.ends_with(".asc") {
            add_ascii_file(&mut tape, &fname[..]);
        } else if fname.ends_with(".bas") {
            add_basic_file(&mut tape, &fname[..]);
        } else {
            add_custom_file(&mut tape, &fname[..]);
        }
        println!("Done");
    }
    let otmp = format!("{}.tmp", path);
    save_tape(&tape, &otmp[..]);
    if tape_exist {
        fs::remove_file(path).unwrap();
    }
    fs::rename(otmp, path).unwrap();
}

fn add_bin_file(tape: &mut tape::Tape, file: &str) {
    let data = &read_file!(file)[..];
    let fname = file_name!(file);
    tape.append_bin(&fname, data);
}

fn add_basic_file(tape: &mut tape::Tape, file: &str) {
    let data = &read_file!(file)[..];
    let fname = file_name!(file);
    tape.append_basic(&fname, data);
}

fn add_ascii_file(tape: &mut tape::Tape, file: &str) {
    let data = &read_file!(file)[..];
    let fname = file_name!(file);
    tape.append_ascii(&fname, data);
}

fn add_custom_file(tape: &mut tape::Tape, file: &str) {
    let data = &read_file!(file)[..];
    tape.append_custom(data);
}

fn save_tape(tape: &tape::Tape, file: &str) {
    let mut ofile = create_file!(&file);
    for block in tape.blocks() {
        write_file!(&file, &mut ofile, block.data());
    }
}
<commit_msg>Integrate export functionality in main program<commit_after>//
// MSX CAS Packager
// Copyright (c) 2015 Alvaro Polo
//
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.

extern crate byteorder;
extern crate docopt;
extern crate rustc_serialize;

#[cfg(test)]
extern crate quickcheck;

mod args;
mod tape;
mod wav;

use std::fs;
use std::fs::File;
use std::io::Read;
use std::io::Write;

#[allow(dead_code)]
fn main() {
    let cmd = args::parse();
    match cmd {
        args::Command::Version => print_version(),
        args::Command::List(path) => list_files(&path[..]),
        args::Command::Add(path, files) =>  add_files(&path[..], &files[..]),
        args::Command::Extract(path) => extract_all(&path[..]),
        args::Command::Export(path, output) => export(&*path, &*output),
    };
}

fn print_version() {
    println!("MSX CAS Packager (MCP) v0.1.0");
    println!("Copyright (C) 2015 Alvaro Polo");
    println!("");
    println!("This program is subject to the terms of the Mozilla Public License v2.0.");
    println!("");
}

macro_rules! open_file {
    ($path: expr) => ({
        match File::open($path) {
            Ok(f) => f,
            Err(e) => {
                println!("Cannot open file '{}': {}", $path, e);
                return
            }
        }
    })
}

macro_rules! create_file {
    ($path: expr) => ({
        match File::create($path) {
            Ok(f) => f,
            Err(e) => {
                println!("Cannot create file '{}': {}", $path, e);
                return
            }
        }
    })
}

macro_rules! read_file {
    ($name: expr, $file: expr, $data: expr) => ({
        match $file.read_to_end($data) {
            Ok(_) => {},
            Err(e) => {
                println!("Cannot read from file '{}': {}", $name, e);
            },
        };
    });
    ($name: expr) => ({
        let file = open_file!($name);
        let mut data: Vec<u8> = vec![];
        read_file!($name, &file, &mut data);
        data
    });
}

macro_rules! write_file {
    ($name: expr, $file: expr, $data: expr) => ({
        match $file.write_all($data) {
            Ok(_) => {},
            Err(e) => {
                println!("Cannot write to file '{}': {}", $name, e);
            },
        };
    })
}

macro_rules! open_tape {
    ($path: expr) => ({
        let mut tape_file = open_file!($path);
        match tape::Tape::read(&mut tape_file) {
            Ok(f) => f,
            Err(e) => {
                println!("Cannot read file '{}': {}", $path, e);
                return
            }
        }
    })
}

macro_rules! open_or_create_tape {
    ($path: expr) => ({
        match File::open($path) {
            Ok(mut f) => {
                match tape::Tape::read(&mut f) {
                    Ok(f) => (f, true),
                    Err(e) => {
                        println!("Cannot read file '{}': {}", $path, e);
                        return
                    }
                }
            },
            Err(_) => (tape::Tape::new(), false),
        }
    })
}

macro_rules! file_name {
    ($file: expr) => ({
        let fname = &$file[..$file.len() - 4];
        if fname.len() > 6 {
            println!("Warning: filename {} is too long, truncating", $file);
        }
        tape::file_name(fname)
    })
}

fn list_files(path: &str) {
    let tape = open_tape!(path);
    for file in tape.files() {
        match file {
            tape::File::Bin(name, begin, end, start, data) => {
                println!("bin    | {:6} | {:5} bytes | [0x{:x},0x{:x}]:0x{:x}",
                    name, data.len(), begin, end, start);
            },
            tape::File::Basic(name, data) => {
                println!("basic  | {:6} | {:5} bytes |", name, data.len());
            },
            tape::File::Ascii(name, data) => {
                let nbytes = data.iter().fold(0, |size, chunk| size + chunk.len());
                println!("ascii  | {:6} | {:5} bytes |", name, nbytes);
            },
            tape::File::Custom(data) => {
                println!("custom |        | {:5} bytes |", data.len());
            }
        };
    }
}

fn extract_all(path: &str) {
    let tape = open_tape!(path);
    let mut next_custom = 0;
    for file in tape.files() {
        let out_path = file.name()
            .map(|n| n.to_string())
            .unwrap_or_else(|| format!("custom.{:03}", { next_custom += 1; next_custom }));
        print!("Extracting {}... ", out_path);
        extract_file(&file, &out_path[..]);
        println!("Done");
    }
}

fn extract_file(file: &tape::File, out_path: &str) {
    let mut ofile = create_file!(out_path);
    match file {
        &tape::File::Bin(_, _, _, _, data) => {
            write_file!(out_path, ofile, data);
        },
        &tape::File::Basic(_, data) => {
            write_file!(out_path, ofile, data);
        },
        &tape::File::Ascii(_, ref chunks) => {
            for chunk in chunks {
                let last = chunk.iter().position(|b| *b == 0x1a).unwrap_or(chunk.len());
                write_file!(out_path, ofile, &chunk[..last]);
            }
        },
        &tape::File::Custom(ref data) => {
            write_file!(out_path, ofile, data);
        },
    }
}

fn add_files(path: &str, files: &[String]) {
    let (mut tape, tape_exist) = open_or_create_tape!(path);
    for fname in files {
        print!("Adding {}... ", fname);
        if fname.ends_with(".bin") {
            add_bin_file(&mut tape, &fname[..]);
        } else if fname.ends_with(".asc") {
            add_ascii_file(&mut tape, &fname[..]);
        } else if fname.ends_with(".bas") {
            add_basic_file(&mut tape, &fname[..]);
        } else {
            add_custom_file(&mut tape, &fname[..]);
        }
        println!("Done");
    }
    let otmp = format!("{}.tmp", path);
    save_tape(&tape, &otmp[..]);
    if tape_exist {
        fs::remove_file(path).unwrap();
    }
    fs::rename(otmp, path).unwrap();
}

fn add_bin_file(tape: &mut tape::Tape, file: &str) {
    let data = &read_file!(file)[..];
    let fname = file_name!(file);
    tape.append_bin(&fname, data);
}

fn add_basic_file(tape: &mut tape::Tape, file: &str) {
    let data = &read_file!(file)[..];
    let fname = file_name!(file);
    tape.append_basic(&fname, data);
}

fn add_ascii_file(tape: &mut tape::Tape, file: &str) {
    let data = &read_file!(file)[..];
    let fname = file_name!(file);
    tape.append_ascii(&fname, data);
}

fn add_custom_file(tape: &mut tape::Tape, file: &str) {
    let data = &read_file!(file)[..];
    tape.append_custom(data);
}

fn save_tape(tape: &tape::Tape, file: &str) {
    let mut ofile = create_file!(&file);
    for block in tape.blocks() {
        write_file!(&file, &mut ofile, block.data());
    }
}

fn export(cas_path: &str, wav_path: &str) {
    let tape = open_tape!(cas_path);
    let mut exporter = wav::Exporter::new();
    let mut wav_file = create_file!(wav_path);

    for (block, i) in tape.blocks().iter().zip(0..tape.blocks().len()) {
        print!("Encoding block {}... ", i);
        let mut nbytes = 0;
        if block.is_file_header() {
            nbytes += exporter.write_long_silence().ok().unwrap();
            nbytes += exporter.write_long_header().ok().unwrap();
        } else {
            nbytes += exporter.write_short_silence().ok().unwrap();
            nbytes += exporter.write_short_header().ok().unwrap();
        }
        nbytes += exporter.write_data(block.data_without_prefix()).ok().unwrap();
        println!("{} KiB", nbytes / 1024);
    }
    exporter.export(&mut wav_file).ok();
}
<|endoftext|>


<commit_before>#![feature(rustc_private, i128_type)]

extern crate getopts;
extern crate miri;
extern crate rustc;
extern crate rustc_driver;
extern crate rustc_errors;
extern crate env_logger;
extern crate log_settings;
extern crate syntax;
extern crate log;

use rustc::session::Session;
use rustc_driver::{Compilation, CompilerCalls, RustcDefaultCalls};
use rustc_driver::driver::{CompileState, CompileController};
use rustc::session::config::{self, Input, ErrorOutputType};
use rustc::hir::{self, itemlikevisit};
use rustc::ty::TyCtxt;
use syntax::ast::{MetaItemKind, NestedMetaItemKind, self};
use std::path::PathBuf;

struct MiriCompilerCalls(RustcDefaultCalls);

impl<'a> CompilerCalls<'a> for MiriCompilerCalls {
    fn early_callback(
        &mut self,
        matches: &getopts::Matches,
        sopts: &config::Options,
        cfg: &ast::CrateConfig,
        descriptions: &rustc_errors::registry::Registry,
        output: ErrorOutputType
    ) -> Compilation {
        self.0.early_callback(matches, sopts, cfg, descriptions, output)
    }
    fn no_input(
        &mut self,
        matches: &getopts::Matches,
        sopts: &config::Options,
        cfg: &ast::CrateConfig,
        odir: &Option<PathBuf>,
        ofile: &Option<PathBuf>,
        descriptions: &rustc_errors::registry::Registry
    ) -> Option<(Input, Option<PathBuf>)> {
        self.0.no_input(matches, sopts, cfg, odir, ofile, descriptions)
    }
    fn late_callback(
        &mut self,
        matches: &getopts::Matches,
        sess: &Session,
        input: &Input,
        odir: &Option<PathBuf>,
        ofile: &Option<PathBuf>
    ) -> Compilation {
        self.0.late_callback(matches, sess, input, odir, ofile)
    }
    fn build_controller(&mut self, sess: &Session, matches: &getopts::Matches) -> CompileController<'a> {
        let mut control = self.0.build_controller(sess, matches);
        control.after_hir_lowering.callback = Box::new(after_hir_lowering);
        control.after_analysis.callback = Box::new(after_analysis);
        if std::env::var("MIRI_HOST_TARGET") != Ok("yes".to_owned()) {
            // only fully compile targets on the host
            control.after_analysis.stop = Compilation::Stop;
        }
        control
    }
}

fn after_hir_lowering(state: &mut CompileState) {
    let attr = (String::from("miri"), syntax::feature_gate::AttributeType::Whitelisted);
    state.session.plugin_attributes.borrow_mut().push(attr);
}

fn after_analysis<'a, 'tcx>(state: &mut CompileState<'a, 'tcx>) {
    state.session.abort_if_errors();

    let tcx = state.tcx.unwrap();
    miri::run_mir_passes(tcx);
    let limits = resource_limits_from_attributes(state);

    if std::env::args().any(|arg| arg == "--test") {
        struct Visitor<'a, 'tcx: 'a>(miri::ResourceLimits, TyCtxt<'a, 'tcx, 'tcx>, &'a CompileState<'a, 'tcx>);
        impl<'a, 'tcx: 'a, 'hir> itemlikevisit::ItemLikeVisitor<'hir> for Visitor<'a, 'tcx> {
            fn visit_item(&mut self, i: &'hir hir::Item) {
                if let hir::Item_::ItemFn(_, _, _, _, _, body_id) = i.node {
                    if i.attrs.iter().any(|attr| attr.value.name == "test") {
                        let did = self.1.hir.body_owner_def_id(body_id);
                        println!("running test: {}", self.1.hir.def_path(did).to_string(self.1));
                        miri::eval_main(self.1, did, self.0);
                        self.2.session.abort_if_errors();
                    }
                }
            }
            fn visit_trait_item(&mut self, _trait_item: &'hir hir::TraitItem) {}
            fn visit_impl_item(&mut self, _impl_item: &'hir hir::ImplItem) {}
        }
        state.hir_crate.unwrap().visit_all_item_likes(&mut Visitor(limits, tcx, state));
    } else {
        if let Some((entry_node_id, _)) = *state.session.entry_fn.borrow() {
            let entry_def_id = tcx.hir.local_def_id(entry_node_id);
            miri::eval_main(tcx, entry_def_id, limits);

            state.session.abort_if_errors();
        } else {
            println!("no main function found, assuming auxiliary build");
        }
    }
}

fn resource_limits_from_attributes(state: &CompileState) -> miri::ResourceLimits {
    let mut limits = miri::ResourceLimits::default();
    let krate = state.hir_crate.as_ref().unwrap();
    let err_msg = "miri attributes need to be in the form `miri(key = value)`";
    let extract_int = |lit: &syntax::ast::Lit| -> u128 {
        match lit.node {
            syntax::ast::LitKind::Int(i, _) => i,
            _ => state.session.span_fatal(lit.span, "expected an integer literal"),
        }
    };

    for attr in krate.attrs.iter().filter(|a| a.name() == "miri") {
        if let MetaItemKind::List(ref items) = attr.value.node {
            for item in items {
                if let NestedMetaItemKind::MetaItem(ref inner) = item.node {
                    if let MetaItemKind::NameValue(ref value) = inner.node {
                        match &inner.name().as_str()[..] {
                            "memory_size" => limits.memory_size = extract_int(value) as u64,
                            "step_limit" => limits.step_limit = extract_int(value) as u64,
                            "stack_limit" => limits.stack_limit = extract_int(value) as usize,
                            _ => state.session.span_err(item.span, "unknown miri attribute"),
                        }
                    } else {
                        state.session.span_err(inner.span, err_msg);
                    }
                } else {
                    state.session.span_err(item.span, err_msg);
                }
            }
        } else {
            state.session.span_err(attr.span, err_msg);
        }
    }
    limits
}

fn init_logger() {
    const MAX_INDENT: usize = 40;

    let format = |record: &log::LogRecord| {
        if record.level() == log::LogLevel::Trace {
            // prepend spaces to indent the final string
            let indentation = log_settings::settings().indentation;
            format!("{lvl}:{module}{depth:2}{indent:<indentation$} {text}",
                lvl = record.level(),
                module = record.location().module_path(),
                depth = indentation / MAX_INDENT,
                indentation = indentation % MAX_INDENT,
                indent = "",
                text = record.args())
        } else {
            format!("{lvl}:{module}: {text}",
                lvl = record.level(),
                module = record.location().module_path(),
                text = record.args())
        }
    };

    let mut builder = env_logger::LogBuilder::new();
    builder.format(format).filter(None, log::LogLevelFilter::Info);

    if std::env::var("MIRI_LOG").is_ok() {
        builder.parse(&std::env::var("MIRI_LOG").unwrap());
    }

    builder.init().unwrap();
}

fn find_sysroot() -> String {
    // Taken from https://github.com/Manishearth/rust-clippy/pull/911.
    let home = option_env!("RUSTUP_HOME").or(option_env!("MULTIRUST_HOME"));
    let toolchain = option_env!("RUSTUP_TOOLCHAIN").or(option_env!("MULTIRUST_TOOLCHAIN"));
    match (home, toolchain) {
        (Some(home), Some(toolchain)) => format!("{}/toolchains/{}", home, toolchain),
        _ => option_env!("RUST_SYSROOT")
            .expect("need to specify RUST_SYSROOT env var or use rustup or multirust")
            .to_owned(),
    }
}

fn main() {
    init_logger();
    let mut args: Vec<String> = std::env::args().collect();

    let sysroot_flag = String::from("--sysroot");
    if !args.contains(&sysroot_flag) {
        args.push(sysroot_flag);
        args.push(find_sysroot());
    }
    // we run the optimization passes inside miri
    // if we ran them twice we'd get funny failures due to borrowck ElaborateDrops only working on
    // unoptimized MIR
    // FIXME: add an after-mir-passes hook to rustc driver
    args.push("-Zmir-opt-level=0".to_owned());
    // for auxilary builds in unit tests
    args.push("-Zalways-encode-mir".to_owned());

    rustc_driver::run_compiler(&args, &mut MiriCompilerCalls(RustcDefaultCalls), None, None);
}
<commit_msg>Simplify logging output.<commit_after>#![feature(rustc_private, i128_type)]

extern crate getopts;
extern crate miri;
extern crate rustc;
extern crate rustc_driver;
extern crate rustc_errors;
extern crate env_logger;
extern crate log_settings;
extern crate syntax;
extern crate log;

use rustc::session::Session;
use rustc_driver::{Compilation, CompilerCalls, RustcDefaultCalls};
use rustc_driver::driver::{CompileState, CompileController};
use rustc::session::config::{self, Input, ErrorOutputType};
use rustc::hir::{self, itemlikevisit};
use rustc::ty::TyCtxt;
use syntax::ast::{MetaItemKind, NestedMetaItemKind, self};
use std::path::PathBuf;

struct MiriCompilerCalls(RustcDefaultCalls);

impl<'a> CompilerCalls<'a> for MiriCompilerCalls {
    fn early_callback(
        &mut self,
        matches: &getopts::Matches,
        sopts: &config::Options,
        cfg: &ast::CrateConfig,
        descriptions: &rustc_errors::registry::Registry,
        output: ErrorOutputType
    ) -> Compilation {
        self.0.early_callback(matches, sopts, cfg, descriptions, output)
    }
    fn no_input(
        &mut self,
        matches: &getopts::Matches,
        sopts: &config::Options,
        cfg: &ast::CrateConfig,
        odir: &Option<PathBuf>,
        ofile: &Option<PathBuf>,
        descriptions: &rustc_errors::registry::Registry
    ) -> Option<(Input, Option<PathBuf>)> {
        self.0.no_input(matches, sopts, cfg, odir, ofile, descriptions)
    }
    fn late_callback(
        &mut self,
        matches: &getopts::Matches,
        sess: &Session,
        input: &Input,
        odir: &Option<PathBuf>,
        ofile: &Option<PathBuf>
    ) -> Compilation {
        self.0.late_callback(matches, sess, input, odir, ofile)
    }
    fn build_controller(&mut self, sess: &Session, matches: &getopts::Matches) -> CompileController<'a> {
        let mut control = self.0.build_controller(sess, matches);
        control.after_hir_lowering.callback = Box::new(after_hir_lowering);
        control.after_analysis.callback = Box::new(after_analysis);
        if std::env::var("MIRI_HOST_TARGET") != Ok("yes".to_owned()) {
            // only fully compile targets on the host
            control.after_analysis.stop = Compilation::Stop;
        }
        control
    }
}

fn after_hir_lowering(state: &mut CompileState) {
    let attr = (String::from("miri"), syntax::feature_gate::AttributeType::Whitelisted);
    state.session.plugin_attributes.borrow_mut().push(attr);
}

fn after_analysis<'a, 'tcx>(state: &mut CompileState<'a, 'tcx>) {
    state.session.abort_if_errors();

    let tcx = state.tcx.unwrap();
    miri::run_mir_passes(tcx);
    let limits = resource_limits_from_attributes(state);

    if std::env::args().any(|arg| arg == "--test") {
        struct Visitor<'a, 'tcx: 'a>(miri::ResourceLimits, TyCtxt<'a, 'tcx, 'tcx>, &'a CompileState<'a, 'tcx>);
        impl<'a, 'tcx: 'a, 'hir> itemlikevisit::ItemLikeVisitor<'hir> for Visitor<'a, 'tcx> {
            fn visit_item(&mut self, i: &'hir hir::Item) {
                if let hir::Item_::ItemFn(_, _, _, _, _, body_id) = i.node {
                    if i.attrs.iter().any(|attr| attr.value.name == "test") {
                        let did = self.1.hir.body_owner_def_id(body_id);
                        println!("running test: {}", self.1.hir.def_path(did).to_string(self.1));
                        miri::eval_main(self.1, did, self.0);
                        self.2.session.abort_if_errors();
                    }
                }
            }
            fn visit_trait_item(&mut self, _trait_item: &'hir hir::TraitItem) {}
            fn visit_impl_item(&mut self, _impl_item: &'hir hir::ImplItem) {}
        }
        state.hir_crate.unwrap().visit_all_item_likes(&mut Visitor(limits, tcx, state));
    } else {
        if let Some((entry_node_id, _)) = *state.session.entry_fn.borrow() {
            let entry_def_id = tcx.hir.local_def_id(entry_node_id);
            miri::eval_main(tcx, entry_def_id, limits);

            state.session.abort_if_errors();
        } else {
            println!("no main function found, assuming auxiliary build");
        }
    }
}

fn resource_limits_from_attributes(state: &CompileState) -> miri::ResourceLimits {
    let mut limits = miri::ResourceLimits::default();
    let krate = state.hir_crate.as_ref().unwrap();
    let err_msg = "miri attributes need to be in the form `miri(key = value)`";
    let extract_int = |lit: &syntax::ast::Lit| -> u128 {
        match lit.node {
            syntax::ast::LitKind::Int(i, _) => i,
            _ => state.session.span_fatal(lit.span, "expected an integer literal"),
        }
    };

    for attr in krate.attrs.iter().filter(|a| a.name() == "miri") {
        if let MetaItemKind::List(ref items) = attr.value.node {
            for item in items {
                if let NestedMetaItemKind::MetaItem(ref inner) = item.node {
                    if let MetaItemKind::NameValue(ref value) = inner.node {
                        match &inner.name().as_str()[..] {
                            "memory_size" => limits.memory_size = extract_int(value) as u64,
                            "step_limit" => limits.step_limit = extract_int(value) as u64,
                            "stack_limit" => limits.stack_limit = extract_int(value) as usize,
                            _ => state.session.span_err(item.span, "unknown miri attribute"),
                        }
                    } else {
                        state.session.span_err(inner.span, err_msg);
                    }
                } else {
                    state.session.span_err(item.span, err_msg);
                }
            }
        } else {
            state.session.span_err(attr.span, err_msg);
        }
    }
    limits
}

fn init_logger() {
    let format = |record: &log::LogRecord| {
        if record.level() == log::LogLevel::Trace {
            // prepend spaces to indent the final string
            let indentation = log_settings::settings().indentation;
            format!(
                "{lvl}:{module}:{indent:<indentation$} {text}",
                lvl = record.level(),
                module = record.location().module_path(),
                indentation = indentation,
                indent = "",
                text = record.args(),
            )
        } else {
            format!(
                "{lvl}:{module}: {text}",
                lvl = record.level(),
                module = record.location().module_path(),
                text = record.args(),
            )
        }
    };

    let mut builder = env_logger::LogBuilder::new();
    builder.format(format).filter(None, log::LogLevelFilter::Info);

    if std::env::var("MIRI_LOG").is_ok() {
        builder.parse(&std::env::var("MIRI_LOG").unwrap());
    }

    builder.init().unwrap();
}

fn find_sysroot() -> String {
    // Taken from https://github.com/Manishearth/rust-clippy/pull/911.
    let home = option_env!("RUSTUP_HOME").or(option_env!("MULTIRUST_HOME"));
    let toolchain = option_env!("RUSTUP_TOOLCHAIN").or(option_env!("MULTIRUST_TOOLCHAIN"));
    match (home, toolchain) {
        (Some(home), Some(toolchain)) => format!("{}/toolchains/{}", home, toolchain),
        _ => option_env!("RUST_SYSROOT")
            .expect("need to specify RUST_SYSROOT env var or use rustup or multirust")
            .to_owned(),
    }
}

fn main() {
    init_logger();
    let mut args: Vec<String> = std::env::args().collect();

    let sysroot_flag = String::from("--sysroot");
    if !args.contains(&sysroot_flag) {
        args.push(sysroot_flag);
        args.push(find_sysroot());
    }
    // we run the optimization passes inside miri
    // if we ran them twice we'd get funny failures due to borrowck ElaborateDrops only working on
    // unoptimized MIR
    // FIXME: add an after-mir-passes hook to rustc driver
    args.push("-Zmir-opt-level=0".to_owned());
    // for auxilary builds in unit tests
    args.push("-Zalways-encode-mir".to_owned());

    rustc_driver::run_compiler(&args, &mut MiriCompilerCalls(RustcDefaultCalls), None, None);
}
<|endoftext|>


<commit_before>#![crate_name = "rboy"]

#![allow(unstable)]

#[macro_use]
extern crate log;

extern crate getopts;

extern crate sdl2;

extern crate rboy;

use rboy::device::Device;
use std::time::Duration;
use std::sync::{Arc,RwLock};
use std::sync::mpsc::{Sender,Receiver};
use std::sync::mpsc::TryRecvError::{Disconnected,Empty};

static SCALE: usize = 2;
static EXITCODE_INCORRECTOPTIONS: isize = 1;
static EXITCODE_CPULOADFAILS: isize = 2;

#[cfg(not(test))]
fn set_exit_status(exitcode: isize)
{
    std::os::set_exit_status(exitcode);
}

fn main() {
	let args = std::os::args();
	let opts = &[ getopts::optflag("s", "serial", "Output serial to stdout"), getopts::optflag("c", "classic", "Force Classic mode") ];
	let matches = match getopts::getopts(args.tail(), opts) {
		Ok(m) => { m }
		Err(f) => { println!("{}", f); return }
	};

	let filename = if !matches.free.is_empty() {
		matches.free[0].clone()
	} else {
		let mut info_start = args[0].clone();
		info_start.push_str(" <filename>");
		println!("{}", getopts::usage(info_start.as_slice(), opts));
		set_exit_status(EXITCODE_INCORRECTOPTIONS);
		return;
	};

	sdl2::init(sdl2::INIT_VIDEO);
	let window = match sdl2::video::Window::new("RBoy - A gameboy in Rust",
												sdl2::video::WindowPos::PosUndefined,
												sdl2::video::WindowPos::PosUndefined,
												160*SCALE as isize,
												144*SCALE as isize,
												sdl2::video::WindowFlags::empty()) {
		Ok(window) => window,
		Err(err) => panic!("failed to open window: {}", err),
	};
	let renderer = match sdl2::render::Renderer::from_window(window, sdl2::render::RenderDriverIndex::Auto, sdl2::render::ACCELERATED) {
		Ok(screen) => screen,
		Err(err) => panic!("failed to open screen: {}", err),
	};

	let (sdl_tx, cpu_rx) = std::sync::mpsc::channel();
	let (cpu_tx, sdl_rx) = std::sync::mpsc::channel();
	let rawscreen = ::std::iter::repeat(0u8).take(160*144*3).collect();
	let arc = Arc::new(RwLock::new(rawscreen));
	let arc2 = arc.clone();

	let cpuloop_thread = std::thread::Thread::scoped(move|| cpuloop(&cpu_tx, &cpu_rx, arc2, filename.as_slice(), &matches));

	let mut timer = std::io::timer::Timer::new().unwrap();
	let periodic = timer.periodic(Duration::milliseconds(8));

	'main : loop {
		let _ = periodic.recv();
		match sdl_rx.try_recv() {
			Err(Disconnected) => { break 'main },
			Ok(_) => recalculate_screen(&renderer, &arc),
			Err(Empty) => {},
		}
		'event : loop {
			match sdl2::event::poll_event() {
				sdl2::event::Event::Quit(_) => break 'main,
				sdl2::event::Event::None => break 'event,
				sdl2::event::Event::KeyDown(_, _, sdl2::keycode::KeyCode::Escape, _, _, _)
					=> break 'main,
				sdl2::event::Event::KeyDown(_, _, sdl2::keycode::KeyCode::LShift, _, _, _)
					=> { let _ = sdl_tx.send(GBEvent::SpeedUp); },
				sdl2::event::Event::KeyUp(_, _, sdl2::keycode::KeyCode::LShift, _, _, _)
					=> { let _ = sdl_tx.send(GBEvent::SlowDown); },
				sdl2::event::Event::KeyDown(_, _, sdlkey, _, _, _) => {
					match sdl_to_keypad(sdlkey) {
						Some(key) =>  { let _ = sdl_tx.send(GBEvent::KeyDown(key)); },
						None => {},
					}
				},
				sdl2::event::Event::KeyUp(_, _, sdlkey, _, _, _) => {
					match sdl_to_keypad(sdlkey) {
						Some(key) => { let _ = sdl_tx.send(GBEvent::KeyUp(key)); },
						None => {},
					}
				},
				_ => {}
			}
		}
	}

    drop(sdl_tx); // Disconnect such that the cpuloop will exit
    let _ = cpuloop_thread.join();
}

fn sdl_to_keypad(key: sdl2::keycode::KeyCode) -> Option<rboy::KeypadKey> {
	match key {
		sdl2::keycode::KeyCode::Z => Some(rboy::KeypadKey::A),
		sdl2::keycode::KeyCode::X => Some(rboy::KeypadKey::B),
		sdl2::keycode::KeyCode::Up => Some(rboy::KeypadKey::Up),
		sdl2::keycode::KeyCode::Down => Some(rboy::KeypadKey::Down),
		sdl2::keycode::KeyCode::Left => Some(rboy::KeypadKey::Left),
		sdl2::keycode::KeyCode::Right => Some(rboy::KeypadKey::Right),
		sdl2::keycode::KeyCode::Space => Some(rboy::KeypadKey::Select),
		sdl2::keycode::KeyCode::Return => Some(rboy::KeypadKey::Start),
		_ => None,
	}
}

fn recalculate_screen(screen: &sdl2::render::Renderer, arc: &Arc<RwLock<Vec<u8>>>) {
	screen.set_draw_color(sdl2::pixels::Color::RGB(0xFF, 0xFF, 0xFF)).unwrap();
	screen.clear().unwrap();

	let data =  arc.read().unwrap().clone();
	for y in range(0, 144) {
		for x in range(0, 160) {
			screen.set_draw_color(sdl2::pixels::Color::RGB(data[y*160*3 + x*3 + 0],
															data[y*160*3 + x*3 + 1],
															data[y*160*3 + x*3 + 2])).unwrap();
			screen.draw_rect(&sdl2::rect::Rect::new((x*SCALE) as i32, (y*SCALE) as i32, SCALE as i32, SCALE as i32)).unwrap();
		}
	}
	screen.present();
}

enum GBEvent {
	KeyUp(rboy::KeypadKey),
	KeyDown(rboy::KeypadKey),
	SpeedUp,
	SlowDown,
}

fn cpuloop(cpu_tx: &Sender<u32>, cpu_rx: &Receiver<GBEvent>, arc: Arc<RwLock<Vec<u8>>>, filename: &str, matches: &getopts::Matches) {
	let opt_c = match matches.opt_present("classic") {
		true => Device::new(filename),
		false => Device::new_cgb(filename),
	};
	let mut c = match opt_c
	{
		Some(cpu) => { cpu },
		None => { error!("Could not get a valid gameboy"); set_exit_status(EXITCODE_CPULOADFAILS); return; },
	};
	c.set_stdout(matches.opt_present("serial"));

	let mut timer = std::io::timer::Timer::new().unwrap();
	let periodic = timer.periodic(Duration::milliseconds(8));
	let mut limit_speed = true;

	let waitticks = (4194.304f32 * 4.0) as u32;

	let mut ticks = 0;
	'cpuloop: loop {
		while ticks < waitticks {
			ticks += c.do_cycle();
			if c.check_and_reset_gpu_updated() {
				let mut data = arc.write().unwrap();
				let gpu_data = c.get_gpu_data();
				for i in range(0, data.len()) { data[i] = gpu_data[i]; }
				if cpu_tx.send(0).is_err() { break 'cpuloop };
			}
		}
		ticks -= waitticks;
		if limit_speed { let _ = periodic.recv(); }

		match cpu_rx.try_recv() {
			Ok(event) => match event {
				GBEvent::KeyUp(key) => c.keyup(key),
				GBEvent::KeyDown(key) => c.keydown(key),
				GBEvent::SpeedUp => limit_speed = false,
				GBEvent::SlowDown => limit_speed = true,
			},
			Err(Empty) => {},
			Err(Disconnected) => { break },
		};
	}
}
<commit_msg>SDL2 type changed<commit_after>#![crate_name = "rboy"]

#![allow(unstable)]

#[macro_use]
extern crate log;

extern crate getopts;

extern crate sdl2;

extern crate rboy;

use rboy::device::Device;
use std::time::Duration;
use std::sync::{Arc,RwLock};
use std::sync::mpsc::{Sender,Receiver};
use std::sync::mpsc::TryRecvError::{Disconnected,Empty};

static SCALE: usize = 2;
static EXITCODE_INCORRECTOPTIONS: isize = 1;
static EXITCODE_CPULOADFAILS: isize = 2;

#[cfg(not(test))]
fn set_exit_status(exitcode: isize)
{
    std::os::set_exit_status(exitcode);
}

fn main() {
	let args = std::os::args();
	let opts = &[ getopts::optflag("s", "serial", "Output serial to stdout"), getopts::optflag("c", "classic", "Force Classic mode") ];
	let matches = match getopts::getopts(args.tail(), opts) {
		Ok(m) => { m }
		Err(f) => { println!("{}", f); return }
	};

	let filename = if !matches.free.is_empty() {
		matches.free[0].clone()
	} else {
		let mut info_start = args[0].clone();
		info_start.push_str(" <filename>");
		println!("{}", getopts::usage(info_start.as_slice(), opts));
		set_exit_status(EXITCODE_INCORRECTOPTIONS);
		return;
	};

	sdl2::init(sdl2::INIT_VIDEO);
	let window = match sdl2::video::Window::new("RBoy - A gameboy in Rust",
												sdl2::video::WindowPos::PosUndefined,
												sdl2::video::WindowPos::PosUndefined,
												160*SCALE as i32,
												144*SCALE as i32,
												sdl2::video::WindowFlags::empty()) {
		Ok(window) => window,
		Err(err) => panic!("failed to open window: {}", err),
	};
	let renderer = match sdl2::render::Renderer::from_window(window, sdl2::render::RenderDriverIndex::Auto, sdl2::render::ACCELERATED) {
		Ok(screen) => screen,
		Err(err) => panic!("failed to open screen: {}", err),
	};

	let (sdl_tx, cpu_rx) = std::sync::mpsc::channel();
	let (cpu_tx, sdl_rx) = std::sync::mpsc::channel();
	let rawscreen = ::std::iter::repeat(0u8).take(160*144*3).collect();
	let arc = Arc::new(RwLock::new(rawscreen));
	let arc2 = arc.clone();

	let cpuloop_thread = std::thread::Thread::scoped(move|| cpuloop(&cpu_tx, &cpu_rx, arc2, filename.as_slice(), &matches));

	let mut timer = std::io::timer::Timer::new().unwrap();
	let periodic = timer.periodic(Duration::milliseconds(8));

	'main : loop {
		let _ = periodic.recv();
		match sdl_rx.try_recv() {
			Err(Disconnected) => { break 'main },
			Ok(_) => recalculate_screen(&renderer, &arc),
			Err(Empty) => {},
		}
		'event : loop {
			match sdl2::event::poll_event() {
				sdl2::event::Event::Quit(_) => break 'main,
				sdl2::event::Event::None => break 'event,
				sdl2::event::Event::KeyDown(_, _, sdl2::keycode::KeyCode::Escape, _, _, _)
					=> break 'main,
				sdl2::event::Event::KeyDown(_, _, sdl2::keycode::KeyCode::LShift, _, _, _)
					=> { let _ = sdl_tx.send(GBEvent::SpeedUp); },
				sdl2::event::Event::KeyUp(_, _, sdl2::keycode::KeyCode::LShift, _, _, _)
					=> { let _ = sdl_tx.send(GBEvent::SlowDown); },
				sdl2::event::Event::KeyDown(_, _, sdlkey, _, _, _) => {
					match sdl_to_keypad(sdlkey) {
						Some(key) =>  { let _ = sdl_tx.send(GBEvent::KeyDown(key)); },
						None => {},
					}
				},
				sdl2::event::Event::KeyUp(_, _, sdlkey, _, _, _) => {
					match sdl_to_keypad(sdlkey) {
						Some(key) => { let _ = sdl_tx.send(GBEvent::KeyUp(key)); },
						None => {},
					}
				},
				_ => {}
			}
		}
	}

    drop(sdl_tx); // Disconnect such that the cpuloop will exit
    let _ = cpuloop_thread.join();
}

fn sdl_to_keypad(key: sdl2::keycode::KeyCode) -> Option<rboy::KeypadKey> {
	match key {
		sdl2::keycode::KeyCode::Z => Some(rboy::KeypadKey::A),
		sdl2::keycode::KeyCode::X => Some(rboy::KeypadKey::B),
		sdl2::keycode::KeyCode::Up => Some(rboy::KeypadKey::Up),
		sdl2::keycode::KeyCode::Down => Some(rboy::KeypadKey::Down),
		sdl2::keycode::KeyCode::Left => Some(rboy::KeypadKey::Left),
		sdl2::keycode::KeyCode::Right => Some(rboy::KeypadKey::Right),
		sdl2::keycode::KeyCode::Space => Some(rboy::KeypadKey::Select),
		sdl2::keycode::KeyCode::Return => Some(rboy::KeypadKey::Start),
		_ => None,
	}
}

fn recalculate_screen(screen: &sdl2::render::Renderer, arc: &Arc<RwLock<Vec<u8>>>) {
	screen.set_draw_color(sdl2::pixels::Color::RGB(0xFF, 0xFF, 0xFF)).unwrap();
	screen.clear().unwrap();

	let data =  arc.read().unwrap().clone();
	for y in range(0, 144) {
		for x in range(0, 160) {
			screen.set_draw_color(sdl2::pixels::Color::RGB(data[y*160*3 + x*3 + 0],
															data[y*160*3 + x*3 + 1],
															data[y*160*3 + x*3 + 2])).unwrap();
			screen.draw_rect(&sdl2::rect::Rect::new((x*SCALE) as i32, (y*SCALE) as i32, SCALE as i32, SCALE as i32)).unwrap();
		}
	}
	screen.present();
}

enum GBEvent {
	KeyUp(rboy::KeypadKey),
	KeyDown(rboy::KeypadKey),
	SpeedUp,
	SlowDown,
}

fn cpuloop(cpu_tx: &Sender<u32>, cpu_rx: &Receiver<GBEvent>, arc: Arc<RwLock<Vec<u8>>>, filename: &str, matches: &getopts::Matches) {
	let opt_c = match matches.opt_present("classic") {
		true => Device::new(filename),
		false => Device::new_cgb(filename),
	};
	let mut c = match opt_c
	{
		Some(cpu) => { cpu },
		None => { error!("Could not get a valid gameboy"); set_exit_status(EXITCODE_CPULOADFAILS); return; },
	};
	c.set_stdout(matches.opt_present("serial"));

	let mut timer = std::io::timer::Timer::new().unwrap();
	let periodic = timer.periodic(Duration::milliseconds(8));
	let mut limit_speed = true;

	let waitticks = (4194.304f32 * 4.0) as u32;

	let mut ticks = 0;
	'cpuloop: loop {
		while ticks < waitticks {
			ticks += c.do_cycle();
			if c.check_and_reset_gpu_updated() {
				let mut data = arc.write().unwrap();
				let gpu_data = c.get_gpu_data();
				for i in range(0, data.len()) { data[i] = gpu_data[i]; }
				if cpu_tx.send(0).is_err() { break 'cpuloop };
			}
		}
		ticks -= waitticks;
		if limit_speed { let _ = periodic.recv(); }

		match cpu_rx.try_recv() {
			Ok(event) => match event {
				GBEvent::KeyUp(key) => c.keyup(key),
				GBEvent::KeyDown(key) => c.keydown(key),
				GBEvent::SpeedUp => limit_speed = false,
				GBEvent::SlowDown => limit_speed = true,
			},
			Err(Empty) => {},
			Err(Disconnected) => { break },
		};
	}
}
<|endoftext|>


<commit_before>use bip_metainfo::MetainfoFile;
use errors::*;

use std::collections::HashMap;
use std::io::Read;
use std::fs;
use std::sync::mpsc::{self, Sender, Receiver};
use std::time::{SystemTime, UNIX_EPOCH};

pub struct BTClient {
    torrents: HashMap<usize, Torrent>,
    id: String, // peer_id or client id
    next_id: usize,
    channels: HashMap<usize, Sender<Message>>,
}

impl BTClient {
    pub fn new() -> BTClient {
        let now = SystemTime::now();
        let duration = now.duration_since(UNIX_EPOCH).unwrap();
        let client_id = "-bittorrent-rs-".to_owned() + &format!("{}", duration.as_secs() % 100_000);
        BTClient {
            torrents: HashMap::new(),
            id: client_id,
            next_id: 0,
            channels: HashMap::new(),
        }
    }

    pub fn add(self: &mut BTClient, file: fs::File) -> Result<usize> {
        let (tx, rx): (Sender<Message>, Receiver<Message>) = mpsc::channel();
        let torrent = Torrent::new(file);
        self.torrents.insert(self.next_id, torrent);
        self.channels.insert(self.next_id, tx);
        self.next_id += 1;
        Ok(self.next_id)
    }

    pub fn remove(self: &mut BTClient, id: usize) -> Result<usize> {
        self.torrents.remove(&id);
        Ok(self.torrents.len())
    }

    pub fn list(self: &BTClient) -> Vec<(usize, String)> {
        self.torrents
            .iter()
            .map(|(id, torrent)| {
                let root_name = torrent.metainfo
                    .info()
                    .files()
                    .next()
                    .unwrap()
                    .paths()
                    .next()
                    .unwrap()
                    .to_owned();
                (*id, root_name)
            })
            .collect()
    }

    pub fn get_id(self: &BTClient) -> String {
        self.id.clone()
    }
}

pub struct Torrent {
    metainfo: MetainfoFile,

    // From/For tracker
    pub peers: Vec<Peer>,
    pub uploaded: usize,
    pub downloaded: usize,
    pub left: usize,
    pub interval: usize, // in seconds
    pub tracker_id: String,
    pub num_seeders: usize,
    pub num_leachers: usize,
}

pub enum Message {
    StartDownload,
    StartSeed,
    StopDownload,
    StopSeed,
    Exit,
}

impl Torrent {
    pub fn new(mut tfile: fs::File) -> Torrent {
        // parse metainfo file
        let mut bytes: Vec<u8> = Vec::new();
        tfile.read_to_end(&mut bytes).unwrap();

        let metainfo = MetainfoFile::from_bytes(bytes).unwrap();

        Torrent {
            metainfo: metainfo,

            peers: Vec::new(),
            uploaded: 0,
            downloaded: 0,
            left: 0,
            interval: 0, // in seconds
            tracker_id: String::new(),
            num_seeders: 0,
            num_leachers: 0,
        }
    }
}

pub struct FileT {
    pub path: String, // can be file or directory name
    pub length: usize,
    pub md5: Option<String>, // optional, try not to use
}

pub struct Peer {
    id: String, // peer_id
    ip_port: String,

    am_choking: bool,
    peer_choking: bool,
    am_interested: bool,
    peer_interested: bool,
}

impl Peer {
    pub fn new(id: String, ip_port: String) -> Peer {
        Peer {
            id: id,
            ip_port: ip_port,
            am_choking: true,
            am_interested: false,
            peer_choking: true,
            peer_interested: false,
        }
    }
}

struct TrackerRequest {
    info_hash: String,
    peer_id: String,
    port: usize, // port client is listening on, between 6881-6889
    uploaded: usize,
    downloaded: usize,
    left: usize,
    event: EventType, // TODO think about adding optional fields
}

enum EventType {
    Started,
    Stopped,
    Completed,
}
<commit_msg>Get either directory name or lone file name as root_name<commit_after>use bip_metainfo::MetainfoFile;
use errors::*;

use std::collections::HashMap;
use std::io::Read;
use std::fs;
use std::sync::mpsc::{self, Sender, Receiver};
use std::time::{SystemTime, UNIX_EPOCH};

pub struct BTClient {
    torrents: HashMap<usize, Torrent>,
    id: String, // peer_id or client id
    next_id: usize,
    channels: HashMap<usize, Sender<Message>>,
}

impl BTClient {
    pub fn new() -> BTClient {
        let now = SystemTime::now();
        let duration = now.duration_since(UNIX_EPOCH).unwrap();
        let client_id = "-bittorrent-rs-".to_owned() + &format!("{}", duration.as_secs() % 100_000);
        BTClient {
            torrents: HashMap::new(),
            id: client_id,
            next_id: 0,
            channels: HashMap::new(),
        }
    }

    pub fn add(self: &mut BTClient, file: fs::File) -> Result<usize> {
        let (tx, rx): (Sender<Message>, Receiver<Message>) = mpsc::channel();
        let torrent = Torrent::new(file);
        self.torrents.insert(self.next_id, torrent);
        self.channels.insert(self.next_id, tx);
        self.next_id += 1;
        Ok(self.next_id)
    }

    pub fn remove(self: &mut BTClient, id: usize) -> Result<usize> {
        self.torrents.remove(&id);
        Ok(self.torrents.len())
    }

    pub fn list(self: &BTClient) -> Vec<(usize, String)> {
        self.torrents
            .iter()
            .map(|(id, torrent)| {
                let root_name: String;
                if let Some(dir) = torrent.metainfo
                    .info()
                    .directory() {
                    root_name = dir.to_owned();
                } else {
                    root_name = torrent.metainfo
                        .info()
                        .files()
                        .next()
                        .unwrap()
                        .paths()
                        .next()
                        .unwrap()
                        .to_owned();
                }
                (*id, root_name)
            })
            .collect()
    }

    pub fn get_id(self: &BTClient) -> String {
        self.id.clone()
    }
}

pub struct Torrent {
    metainfo: MetainfoFile,

    // From/For tracker
    pub peers: Vec<Peer>,
    pub uploaded: usize,
    pub downloaded: usize,
    pub left: usize,
    pub interval: usize, // in seconds
    pub tracker_id: String,
    pub num_seeders: usize,
    pub num_leachers: usize,
}

pub enum Message {
    StartDownload,
    StartSeed,
    StopDownload,
    StopSeed,
    Exit,
}

impl Torrent {
    pub fn new(mut tfile: fs::File) -> Torrent {
        // parse metainfo file
        let mut bytes: Vec<u8> = Vec::new();
        tfile.read_to_end(&mut bytes).unwrap();

        let metainfo = MetainfoFile::from_bytes(bytes).unwrap();

        Torrent {
            metainfo: metainfo,

            peers: Vec::new(),
            uploaded: 0,
            downloaded: 0,
            left: 0,
            interval: 0, // in seconds
            tracker_id: String::new(),
            num_seeders: 0,
            num_leachers: 0,
        }
    }
}

pub struct FileT {
    pub path: String, // can be file or directory name
    pub length: usize,
    pub md5: Option<String>, // optional, try not to use
}

pub struct Peer {
    id: String, // peer_id
    ip_port: String,

    am_choking: bool,
    peer_choking: bool,
    am_interested: bool,
    peer_interested: bool,
}

impl Peer {
    pub fn new(id: String, ip_port: String) -> Peer {
        Peer {
            id: id,
            ip_port: ip_port,
            am_choking: true,
            am_interested: false,
            peer_choking: true,
            peer_interested: false,
        }
    }
}

struct TrackerRequest {
    info_hash: String,
    peer_id: String,
    port: usize, // port client is listening on, between 6881-6889
    uploaded: usize,
    downloaded: usize,
    left: usize,
    event: EventType, // TODO think about adding optional fields
}

enum EventType {
    Started,
    Stopped,
    Completed,
}
<|endoftext|>


<commit_before>use exchange::{ Exchange, ExchangeApi };
use pair::Pair;
use bitstamp::api::BitstampApi;

use std::collections::HashMap;
use serde_json::value::Map;
use serde_json::value::Value;

#[derive(Debug)]
#[derive(PartialEq)]
pub enum Coinnect {
    BitstampApi
}

impl Coinnect {
    /// Create a new CoinnectApi by providing an API key & API secret
    pub fn new(exchange: Exchange, customer_id: &str, api_key: &str, api_secret: &str) -> Box<ExchangeApi> {

        let mut params = HashMap::new();
        params.insert("customer_id", customer_id);
        params.insert("api_key", api_key);
        params.insert("api_secret", api_secret);

        match exchange {
            Exchange::Bitstamp => Box::new(BitstampApi::new(&params)),
            Exchange::Kraken => Box::new(UnimplementedApi),
            Exchange::Poloniex => Box::new(UnimplementedApi),
        }
    }
}

#[derive(Debug)]
struct UnimplementedApi;

impl ExchangeApi for UnimplementedApi {
    fn public_query(&mut self, _: &HashMap<&str, &str>) -> Option<Map<String, Value>> {
        panic!("Not implemented");
    }
    fn private_query(&mut self, _: &HashMap<&str, &str>) -> Option<Map<String, Value>> {
        panic!("Not implemented");
    }

    fn return_ticker(&mut self, pair: Pair) -> Option<Map<String, Value>> {
        panic!("Not implemented");
    }
    fn return_order_book(&mut self, _: &str) -> Option<Map<String, Value>> {
        panic!("Not implemented");
    }
    fn return_balances(&mut self, _: &str) -> Option<Map<String, Value>> {
        panic!("Not implemented");
    }
}
<commit_msg>Implement new_from_file for Coinnect<commit_after>use exchange::{ Exchange, ExchangeApi };
use pair::Pair;
use bitstamp::api::BitstampApi;

use std::collections::HashMap;
use std::path::PathBuf;
use serde_json::value::Map;
use serde_json::value::Value;

#[derive(Debug)]
#[derive(PartialEq)]
pub enum Coinnect {
    BitstampApi
}

impl Coinnect {
    /// Create a new CoinnectApi by providing an API key & API secret
    pub fn new(exchange: Exchange, customer_id: &str, api_key: &str, api_secret: &str) -> Box<ExchangeApi> {

        let mut params = HashMap::new();
        params.insert("customer_id", customer_id);
        params.insert("api_key", api_key);
        params.insert("api_secret", api_secret);

        match exchange {
            Exchange::Bitstamp => Box::new(BitstampApi::new(&params)),
            Exchange::Kraken => Box::new(UnimplementedApi),
            Exchange::Poloniex => Box::new(UnimplementedApi),
        }
    }

    /// Create a new CoinnectApi from a json configuration file. This file must follow this
    /// structure:
    ///
    /// For this example, you could use load your Bitstamp account with
    /// `new_from_file(Exchange::Bitstamp, Path::new("/keys.json"))`
    pub fn new_from_file(exchange: Exchange, path: PathBuf) -> Box<ExchangeApi> {

        match exchange {
            Exchange::Bitstamp => Box::new(BitstampApi::new_from_file("account_bitstamp", path)),
            Exchange::Kraken => Box::new(UnimplementedApi),
            Exchange::Poloniex => Box::new(UnimplementedApi),
        }
    }
}

#[derive(Debug)]
struct UnimplementedApi;

impl ExchangeApi for UnimplementedApi {
    fn public_query(&mut self, _: &HashMap<&str, &str>) -> Option<Map<String, Value>> {
        panic!("Not implemented");
    }
    fn private_query(&mut self, _: &HashMap<&str, &str>) -> Option<Map<String, Value>> {
        panic!("Not implemented");
    }

    fn return_ticker(&mut self, _: Pair) -> Option<Map<String, Value>> {
        panic!("Not implemented");
    }
    fn return_order_book(&mut self, _: &str) -> Option<Map<String, Value>> {
        panic!("Not implemented");
    }
    fn return_balances(&mut self, _: &str) -> Option<Map<String, Value>> {
        panic!("Not implemented");
    }
}
<|endoftext|>


<commit_before>use std::vec::Vec;
use std::string::String;

struct Compiler {
    pub lines: Vec<String>,
}

impl Compiler {
    pub fn new() -> Self {
        Compiler { lines: Vec::new() }
    }

    pub fn parse(&mut self, assembly: &str) {
        let mut line = String::new();
        let mut chars = assembly.chars();

        while let Some(c) = chars.next() {
            match c {
                // Line Feed | Vertical Tab | Form Feed | Next Line
                '\u{000A}' | '\u{000B}' | '\u{000C}' | '\u{0085}' => {
                    self.lines.push(line);
                    line = String::new();
                }

                // Carriage Return
                '\u{000D}' => {
                    self.lines.push(line);
                    line = String::new();

                    // Carriage Return + Line Feed
                    match chars.next() {
                        Some(n) => {
                            if n != '\u{000A}' {
                                line.push(n);
                            }
                        }
                        None => {}
                    }
                }

                _ => {
                    line.push(c);
                }
            }
        }

        if !line.is_empty() {
            self.lines.push(line);
        }
    }
}

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

    #[test]
    fn it_splits_lines_by_line_feed() {
        let mut compiler = Compiler::new();
        compiler.parse("0 0 0 0\n0 0 0 0");

        assert_eq!(compiler.lines.len(), 2);
    }

    #[test]
    fn it_splits_lines_by_vertical_tab() {
        let mut compiler = Compiler::new();
        compiler.parse("0 0 0 0\x0B0 0 0 0");

        assert_eq!(compiler.lines.len(), 2);
    }

    #[test]
    fn it_splits_lines_by_form_feed() {
        let mut compiler = Compiler::new();
        compiler.parse("0 0 0 0\x0C0 0 0 0");

        assert_eq!(compiler.lines.len(), 2);
    }

    #[test]
    fn it_splits_lines_by_carriage_return() {
        let mut compiler = Compiler::new();
        compiler.parse("0 0 0 0\r0 0 0 0");

        assert_eq!(compiler.lines.len(), 2);
    }

    #[test]
    fn it_splits_lines_by_carriage_return_line_feed() {
        let mut compiler = Compiler::new();
        compiler.parse("0 0 0 0\r\n0 0 0 0");

        assert_eq!(compiler.lines.len(), 2);
    }

    #[test]
    fn it_splits_lines_by_next_line() {
        let mut compiler = Compiler::new();
        compiler.parse("0 0 0 0\u{0085}0 0 0 0");

        assert_eq!(compiler.lines.len(), 2);
    }

    #[test]
    fn it_ignors_trailing_separators() {
        let mut compiler = Compiler::new();
        compiler.parse("0 0 0 0\r\n0 0 0 0\r\n");

        assert_eq!(compiler.lines.len(), 2);
    }
}
<commit_msg>Split assembly on line/paragraph separators.<commit_after>use std::vec::Vec;
use std::string::String;

struct Compiler {
    pub lines: Vec<String>,
}

impl Compiler {
    pub fn new() -> Self {
        Compiler { lines: Vec::new() }
    }

    pub fn parse(&mut self, assembly: &str) {
        let mut line = String::new();
        let mut chars = assembly.chars();

        while let Some(c) = chars.next() {
            match c {
                // Line Feed | Vertical Tab | Form Feed | Next Line | Line/Paragraph Separator
                '\u{000A}' | '\u{000B}' | '\u{000C}' | '\u{0085}' | '\u{2028}' | '\u{2029}' => {
                    self.lines.push(line);
                    line = String::new();
                }

                // Carriage Return
                '\u{000D}' => {
                    self.lines.push(line);
                    line = String::new();

                    // Carriage Return + Line Feed
                    match chars.next() {
                        Some(n) => {
                            if n != '\u{000A}' {
                                line.push(n);
                            }
                        }
                        None => {}
                    }
                }

                _ => {
                    line.push(c);
                }
            }
        }

        if !line.is_empty() {
            self.lines.push(line);
        }
    }
}

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

    #[test]
    fn it_splits_lines_by_line_feed() {
        let mut compiler = Compiler::new();
        compiler.parse("0 0 0 0\n0 0 0 0");

        assert_eq!(compiler.lines.len(), 2);
    }

    #[test]
    fn it_splits_lines_by_vertical_tab() {
        let mut compiler = Compiler::new();
        compiler.parse("0 0 0 0\x0B0 0 0 0");

        assert_eq!(compiler.lines.len(), 2);
    }

    #[test]
    fn it_splits_lines_by_form_feed() {
        let mut compiler = Compiler::new();
        compiler.parse("0 0 0 0\x0C0 0 0 0");

        assert_eq!(compiler.lines.len(), 2);
    }

    #[test]
    fn it_splits_lines_by_carriage_return() {
        let mut compiler = Compiler::new();
        compiler.parse("0 0 0 0\r0 0 0 0");

        assert_eq!(compiler.lines.len(), 2);
    }

    #[test]
    fn it_splits_lines_by_carriage_return_line_feed() {
        let mut compiler = Compiler::new();
        compiler.parse("0 0 0 0\r\n0 0 0 0");

        assert_eq!(compiler.lines.len(), 2);
    }

    #[test]
    fn it_splits_lines_by_next_line() {
        let mut compiler = Compiler::new();
        compiler.parse("0 0 0 0\u{0085}0 0 0 0");

        assert_eq!(compiler.lines.len(), 2);
    }

    #[test]
    fn it_splits_lines_by_line_separator() {
        let mut compiler = Compiler::new();
        compiler.parse("0 0 0 0\u{2028}0 0 0 0");

        assert_eq!(compiler.lines.len(), 2);
    }

    #[test]
    fn it_splits_lines_by_paragraph_separator() {
        let mut compiler = Compiler::new();
        compiler.parse("0 0 0 0\u{2029}0 0 0 0");

        assert_eq!(compiler.lines.len(), 2);
    }

    #[test]
    fn it_ignors_trailing_separators() {
        let mut compiler = Compiler::new();
        compiler.parse("0 0 0 0\r\n0 0 0 0\r\n");

        assert_eq!(compiler.lines.len(), 2);
    }
}
<|endoftext|>


<commit_before>use crate::alloc::vec::Vec;
use parity_wasm::elements::{self, Deserialize};
use std::borrow::Cow;
use std::slice;
use std::u64;

use crate::{
    Machine, Object, ObjectSection, ObjectSegment, Relocation, SectionKind, Symbol, SymbolMap,
};

/// A WebAssembly object file.
#[derive(Debug)]
pub struct WasmFile {
    module: elements::Module,
}

impl<'data> WasmFile {
    /// Parse the raw wasm data.
    pub fn parse(mut data: &'data [u8]) -> Result<Self, &'static str> {
        let module =
            elements::Module::deserialize(&mut data).map_err(|_| "failed to parse wasm")?;
        Ok(WasmFile { module })
    }
}

/// An iterator over the segments of an `WasmFile`.
#[derive(Debug)]
pub struct WasmSegmentIterator<'file> {
    file: &'file WasmFile,
}

/// A segment of an `WasmFile`.
#[derive(Debug)]
pub struct WasmSegment<'file> {
    file: &'file WasmFile,
}

/// An iterator over the sections of an `WasmFile`.
#[derive(Debug)]
pub struct WasmSectionIterator<'file> {
    sections: slice::Iter<'file, elements::Section>,
}

/// A section of an `WasmFile`.
#[derive(Debug)]
pub struct WasmSection<'file> {
    section: &'file elements::Section,
}

/// An iterator over the symbols of an `WasmFile`.
#[derive(Debug)]
pub struct WasmSymbolIterator<'file> {
    file: &'file WasmFile,
}

/// An iterator over the relocations in an `WasmSection`.
#[derive(Debug)]
pub struct WasmRelocationIterator;

fn serialize_to_cow<'a, S>(s: S) -> Option<Cow<'a, [u8]>>
where
    S: elements::Serialize,
{
    let mut buf = Vec::new();
    s.serialize(&mut buf).ok()?;
    Some(Cow::from(buf))
}

impl<'file> Object<'static, 'file> for WasmFile {
    type Segment = WasmSegment<'file>;
    type SegmentIterator = WasmSegmentIterator<'file>;
    type Section = WasmSection<'file>;
    type SectionIterator = WasmSectionIterator<'file>;
    type SymbolIterator = WasmSymbolIterator<'file>;

    fn machine(&self) -> Machine {
        Machine::Other
    }

    fn segments(&'file self) -> Self::SegmentIterator {
        WasmSegmentIterator { file: self }
    }

    fn entry(&'file self) -> u64 {
        self.module.start_section().map_or(u64::MAX, u64::from)
    }

    fn section_by_name(&'file self, section_name: &str) -> Option<WasmSection<'file>> {
        for s in self.module.sections() {
            let section = WasmSection { section: s };
            if section.name() == Some(section_name) {
                return Some(section);
            }
        }
        None
    }

    fn sections(&'file self) -> Self::SectionIterator {
        WasmSectionIterator {
            sections: self.module.sections().iter(),
        }
    }

    fn symbol_by_index(&self, _index: u64) -> Option<Symbol<'static>> {
        unimplemented!()
    }

    fn symbols(&'file self) -> Self::SymbolIterator {
        WasmSymbolIterator { file: self }
    }

    fn dynamic_symbols(&'file self) -> Self::SymbolIterator {
        WasmSymbolIterator { file: self }
    }

    fn symbol_map(&self) -> SymbolMap<'static> {
        SymbolMap {
            symbols: Vec::new(),
        }
    }

    fn is_little_endian(&self) -> bool {
        true
    }

    fn has_debug_symbols(&self) -> bool {
        // We ignore the "name" section, and use this to mean whether the wasm
        // has DWARF.
        self.module.sections().iter().any(|s| match *s {
            elements::Section::Custom(ref c) => c.name().starts_with(".debug_"),
            _ => false,
        })
    }
}

impl<'file> Iterator for WasmSegmentIterator<'file> {
    type Item = WasmSegment<'file>;

    fn next(&mut self) -> Option<Self::Item> {
        None
    }
}

impl<'file> ObjectSegment<'static> for WasmSegment<'file> {
    #[inline]
    fn address(&self) -> u64 {
        unreachable!()
    }

    #[inline]
    fn size(&self) -> u64 {
        unreachable!()
    }

    fn data(&self) -> &'static [u8] {
        unreachable!()
    }

    #[inline]
    fn name(&self) -> Option<&str> {
        unreachable!()
    }
}

impl<'file> Iterator for WasmSectionIterator<'file> {
    type Item = WasmSection<'file>;

    fn next(&mut self) -> Option<Self::Item> {
        self.sections.next().map(|s| WasmSection { section: s })
    }
}

impl<'file> ObjectSection<'static> for WasmSection<'file> {
    type RelocationIterator = WasmRelocationIterator;

    #[inline]
    fn address(&self) -> u64 {
        1
    }

    #[inline]
    fn size(&self) -> u64 {
        serialize_to_cow(self.section.clone()).map_or(0, |b| b.len() as u64)
    }

    fn data(&self) -> Cow<'static, [u8]> {
        match *self.section {
            elements::Section::Start(section) => {
                serialize_to_cow(elements::VarUint32::from(section))
            }
            _ => serialize_to_cow(self.section.clone()),
        }
        .unwrap_or_else(|| Cow::from(&[][..]))
    }

    #[inline]
    fn uncompressed_data(&self) -> Cow<'static, [u8]> {
        // TODO: does wasm support compression?
        self.data()
    }

    fn name(&self) -> Option<&str> {
        match *self.section {
            elements::Section::Unparsed { .. } => None,
            elements::Section::Custom(ref c) => Some(c.name()),
            elements::Section::Type(_) => Some("Type"),
            elements::Section::Import(_) => Some("Import"),
            elements::Section::Function(_) => Some("Function"),
            elements::Section::Table(_) => Some("Table"),
            elements::Section::Memory(_) => Some("Memory"),
            elements::Section::Global(_) => Some("Global"),
            elements::Section::Export(_) => Some("Export"),
            elements::Section::Start(_) => Some("Start"),
            elements::Section::Element(_) => Some("Element"),
            elements::Section::Code(_) => Some("Code"),
            elements::Section::DataCount(_) => Some("DataCount"),
            elements::Section::Data(_) => Some("Data"),
            elements::Section::Name(_) => Some("Name"),
            elements::Section::Reloc(_) => Some("Reloc"),
        }
    }

    #[inline]
    fn segment_name(&self) -> Option<&str> {
        None
    }

    fn kind(&self) -> SectionKind {
        match *self.section {
            elements::Section::Unparsed { .. } => SectionKind::Unknown,
            elements::Section::Custom(_) => SectionKind::Unknown,
            elements::Section::Type(_) => SectionKind::Other,
            elements::Section::Import(_) => SectionKind::Other,
            elements::Section::Function(_) => SectionKind::Other,
            elements::Section::Table(_) => SectionKind::Other,
            elements::Section::Memory(_) => SectionKind::Other,
            elements::Section::Global(_) => SectionKind::Other,
            elements::Section::Export(_) => SectionKind::Other,
            elements::Section::Start(_) => SectionKind::Other,
            elements::Section::Element(_) => SectionKind::Other,
            elements::Section::Code(_) => SectionKind::Text,
            elements::Section::DataCount(_) => SectionKind::Other,
            elements::Section::Data(_) => SectionKind::Data,
            elements::Section::Name(_) => SectionKind::Other,
            elements::Section::Reloc(_) => SectionKind::Other,
        }
    }

    fn relocations(&self) -> WasmRelocationIterator {
        WasmRelocationIterator
    }
}

impl<'file> Iterator for WasmSymbolIterator<'file> {
    type Item = Symbol<'static>;

    fn next(&mut self) -> Option<Self::Item> {
        unimplemented!()
    }
}

impl Iterator for WasmRelocationIterator {
    type Item = (u64, Relocation);

    fn next(&mut self) -> Option<Self::Item> {
        None
    }
}
<commit_msg>Fix WasmSection::data<commit_after>use crate::alloc::vec::Vec;
use parity_wasm::elements::{self, Deserialize};
use std::borrow::Cow;
use std::slice;
use std::u64;

use crate::{
    Machine, Object, ObjectSection, ObjectSegment, Relocation, SectionKind, Symbol, SymbolMap,
};

/// A WebAssembly object file.
#[derive(Debug)]
pub struct WasmFile {
    module: elements::Module,
}

impl<'data> WasmFile {
    /// Parse the raw wasm data.
    pub fn parse(mut data: &'data [u8]) -> Result<Self, &'static str> {
        let module =
            elements::Module::deserialize(&mut data).map_err(|_| "failed to parse wasm")?;
        Ok(WasmFile { module })
    }
}

/// An iterator over the segments of an `WasmFile`.
#[derive(Debug)]
pub struct WasmSegmentIterator<'file> {
    file: &'file WasmFile,
}

/// A segment of an `WasmFile`.
#[derive(Debug)]
pub struct WasmSegment<'file> {
    file: &'file WasmFile,
}

/// An iterator over the sections of an `WasmFile`.
#[derive(Debug)]
pub struct WasmSectionIterator<'file> {
    sections: slice::Iter<'file, elements::Section>,
}

/// A section of an `WasmFile`.
#[derive(Debug)]
pub struct WasmSection<'file> {
    section: &'file elements::Section,
}

/// An iterator over the symbols of an `WasmFile`.
#[derive(Debug)]
pub struct WasmSymbolIterator<'file> {
    file: &'file WasmFile,
}

/// An iterator over the relocations in an `WasmSection`.
#[derive(Debug)]
pub struct WasmRelocationIterator;

fn serialize_to_cow<'a, S>(s: S) -> Option<Cow<'a, [u8]>>
where
    S: elements::Serialize,
{
    let mut buf = Vec::new();
    s.serialize(&mut buf).ok()?;
    Some(Cow::from(buf))
}

impl<'file> Object<'static, 'file> for WasmFile {
    type Segment = WasmSegment<'file>;
    type SegmentIterator = WasmSegmentIterator<'file>;
    type Section = WasmSection<'file>;
    type SectionIterator = WasmSectionIterator<'file>;
    type SymbolIterator = WasmSymbolIterator<'file>;

    fn machine(&self) -> Machine {
        Machine::Other
    }

    fn segments(&'file self) -> Self::SegmentIterator {
        WasmSegmentIterator { file: self }
    }

    fn entry(&'file self) -> u64 {
        self.module.start_section().map_or(u64::MAX, u64::from)
    }

    fn section_by_name(&'file self, section_name: &str) -> Option<WasmSection<'file>> {
        for s in self.module.sections() {
            let section = WasmSection { section: s };
            if section.name() == Some(section_name) {
                return Some(section);
            }
        }
        None
    }

    fn sections(&'file self) -> Self::SectionIterator {
        WasmSectionIterator {
            sections: self.module.sections().iter(),
        }
    }

    fn symbol_by_index(&self, _index: u64) -> Option<Symbol<'static>> {
        unimplemented!()
    }

    fn symbols(&'file self) -> Self::SymbolIterator {
        WasmSymbolIterator { file: self }
    }

    fn dynamic_symbols(&'file self) -> Self::SymbolIterator {
        WasmSymbolIterator { file: self }
    }

    fn symbol_map(&self) -> SymbolMap<'static> {
        SymbolMap {
            symbols: Vec::new(),
        }
    }

    fn is_little_endian(&self) -> bool {
        true
    }

    fn has_debug_symbols(&self) -> bool {
        // We ignore the "name" section, and use this to mean whether the wasm
        // has DWARF.
        self.module.sections().iter().any(|s| match *s {
            elements::Section::Custom(ref c) => c.name().starts_with(".debug_"),
            _ => false,
        })
    }
}

impl<'file> Iterator for WasmSegmentIterator<'file> {
    type Item = WasmSegment<'file>;

    fn next(&mut self) -> Option<Self::Item> {
        None
    }
}

impl<'file> ObjectSegment<'static> for WasmSegment<'file> {
    #[inline]
    fn address(&self) -> u64 {
        unreachable!()
    }

    #[inline]
    fn size(&self) -> u64 {
        unreachable!()
    }

    fn data(&self) -> &'static [u8] {
        unreachable!()
    }

    #[inline]
    fn name(&self) -> Option<&str> {
        unreachable!()
    }
}

impl<'file> Iterator for WasmSectionIterator<'file> {
    type Item = WasmSection<'file>;

    fn next(&mut self) -> Option<Self::Item> {
        self.sections.next().map(|s| WasmSection { section: s })
    }
}

impl<'file> ObjectSection<'static> for WasmSection<'file> {
    type RelocationIterator = WasmRelocationIterator;

    #[inline]
    fn address(&self) -> u64 {
        1
    }

    #[inline]
    fn size(&self) -> u64 {
        serialize_to_cow(self.section.clone()).map_or(0, |b| b.len() as u64)
    }

    fn data(&self) -> Cow<'static, [u8]> {
        match *self.section {
            elements::Section::Custom(ref section) => Some(section.payload().to_vec().into()),
            elements::Section::Start(section) => {
                serialize_to_cow(elements::VarUint32::from(section))
            }
            _ => serialize_to_cow(self.section.clone()),
        }
        .unwrap_or_else(|| Cow::from(&[][..]))
    }

    #[inline]
    fn uncompressed_data(&self) -> Cow<'static, [u8]> {
        // TODO: does wasm support compression?
        self.data()
    }

    fn name(&self) -> Option<&str> {
        match *self.section {
            elements::Section::Unparsed { .. } => None,
            elements::Section::Custom(ref c) => Some(c.name()),
            elements::Section::Type(_) => Some("Type"),
            elements::Section::Import(_) => Some("Import"),
            elements::Section::Function(_) => Some("Function"),
            elements::Section::Table(_) => Some("Table"),
            elements::Section::Memory(_) => Some("Memory"),
            elements::Section::Global(_) => Some("Global"),
            elements::Section::Export(_) => Some("Export"),
            elements::Section::Start(_) => Some("Start"),
            elements::Section::Element(_) => Some("Element"),
            elements::Section::Code(_) => Some("Code"),
            elements::Section::DataCount(_) => Some("DataCount"),
            elements::Section::Data(_) => Some("Data"),
            elements::Section::Name(_) => Some("Name"),
            elements::Section::Reloc(_) => Some("Reloc"),
        }
    }

    #[inline]
    fn segment_name(&self) -> Option<&str> {
        None
    }

    fn kind(&self) -> SectionKind {
        match *self.section {
            elements::Section::Unparsed { .. } => SectionKind::Unknown,
            elements::Section::Custom(_) => SectionKind::Unknown,
            elements::Section::Type(_) => SectionKind::Other,
            elements::Section::Import(_) => SectionKind::Other,
            elements::Section::Function(_) => SectionKind::Other,
            elements::Section::Table(_) => SectionKind::Other,
            elements::Section::Memory(_) => SectionKind::Other,
            elements::Section::Global(_) => SectionKind::Other,
            elements::Section::Export(_) => SectionKind::Other,
            elements::Section::Start(_) => SectionKind::Other,
            elements::Section::Element(_) => SectionKind::Other,
            elements::Section::Code(_) => SectionKind::Text,
            elements::Section::DataCount(_) => SectionKind::Other,
            elements::Section::Data(_) => SectionKind::Data,
            elements::Section::Name(_) => SectionKind::Other,
            elements::Section::Reloc(_) => SectionKind::Other,
        }
    }

    fn relocations(&self) -> WasmRelocationIterator {
        WasmRelocationIterator
    }
}

impl<'file> Iterator for WasmSymbolIterator<'file> {
    type Item = Symbol<'static>;

    fn next(&mut self) -> Option<Self::Item> {
        unimplemented!()
    }
}

impl Iterator for WasmRelocationIterator {
    type Item = (u64, Relocation);

    fn next(&mut self) -> Option<Self::Item> {
        None
    }
}
<|endoftext|>


<commit_before>mod faux_stdout;

use self::faux_stdout::FauxStdout;
use std::io::{Read};
use std::fs::File;
use std::str;
use thoughtfuck::vm::*;
use thoughtfuck::program::*;
use thoughtfuck::parse::parse;

fn read_file(filename: &str) -> String {
    let mut file = File::open(filename).unwrap();
    let mut source = String::new();
    file.read_to_string(&mut source).unwrap();
    source
}

pub fn test_output(input_filename: &str, expected_answer_filename: &str) {
    let source = read_file(input_filename);

    let commands = parse(&source);

    let mut program = Program::new();
    program.append(&commands);

    let mut stdout = FauxStdout::new();
    {
        let mut vm = VM::new(&mut stdout);
        program.execute(&mut vm);
    }
    assert_eq!(stdout.buffer, read_file(expected_answer_filename));
}
<commit_msg>Slim imports in common<commit_after>mod faux_stdout;

use self::faux_stdout::FauxStdout;
use std::io::Read;
use std::fs::File;
use thoughtfuck::vm::VM;
use thoughtfuck::program::Program;
use thoughtfuck::parse::parse;

fn read_file(filename: &str) -> String {
    let mut file = File::open(filename).unwrap();
    let mut source = String::new();
    file.read_to_string(&mut source).unwrap();
    source
}

pub fn test_output(input_filename: &str, expected_answer_filename: &str) {
    let source = read_file(input_filename);

    let commands = parse(&source);

    let mut program = Program::new();
    program.append(&commands);

    let mut stdout = FauxStdout::new();
    {
        let mut vm = VM::new(&mut stdout);
        program.execute(&mut vm);
    }
    assert_eq!(stdout.buffer, read_file(expected_answer_filename));
}
<|endoftext|>


<commit_before>use crate::rt::compute_raw_varint32_size;
use crate::rt::tag_size;
use crate::rt::ProtobufFixed;
use crate::rt::ProtobufVarint;
use crate::rt::ProtobufVarintZigzag;
use crate::Enum;
use crate::EnumOrUnknown;

/// Size of serialized repeated packed field, excluding length and tag.
pub fn vec_packed_varint_data_size<T: ProtobufVarint>(vec: &[T]) -> u64 {
    vec.iter()
        .map(|v| v.len_varint() as u64)
        .fold(0, |a, i| a + i)
}

/// Size of serialized repeated packed field, excluding length and tag.
pub fn vec_packed_varint_zigzag_data_size<T: ProtobufVarintZigzag>(vec: &[T]) -> u64 {
    vec.iter()
        .map(|v| v.len_varint_zigzag())
        .fold(0, |a, i| a + i)
}

/// Size of serialized repeated packed enum field, excluding length and tag.
pub fn vec_packed_enum_or_unknown_data_size<E: Enum>(vec: &[EnumOrUnknown<E>]) -> u64 {
    vec.iter()
        .map(|e| compute_raw_varint32_size(e.value() as u32))
        .fold(0, |a, i| a + i)
}

/// Size of serialized data with length prefix and tag
pub fn vec_packed_varint_size<T: ProtobufVarint>(field_number: u32, vec: &[T]) -> u64 {
    if vec.is_empty() {
        0
    } else {
        let data_size = vec_packed_varint_data_size(vec);
        tag_size(field_number) + data_size.len_varint() + data_size
    }
}

/// Size of serialized data with length prefix and tag
pub fn vec_packed_varint_zigzag_size<T: ProtobufVarintZigzag>(field_number: u32, vec: &[T]) -> u64 {
    if vec.is_empty() {
        0
    } else {
        let data_size = vec_packed_varint_zigzag_data_size(vec);
        tag_size(field_number) + data_size.len_varint() + data_size
    }
}

/// Size of serialized data with length prefix and tag
pub fn vec_packed_enum_or_unknown_size<E: Enum>(
    field_number: u32,
    vec: &[EnumOrUnknown<E>],
) -> u64 {
    if vec.is_empty() {
        0
    } else {
        let data_size = vec_packed_enum_or_unknown_data_size(vec);
        tag_size(field_number) + data_size.len_varint() + data_size
    }
}

/// Compute data size of fixed encoding of repeated field data.
pub(crate) fn vec_packed_fixed_data_size<V: ProtobufFixed>(vec: &[V]) -> u64 {
    (vec.len() as u64) * (V::LEN as u64)
}

/// Compute field size (data plus header) of fixed encoding of repeated field.
pub fn vec_packed_fixed_size<V: ProtobufFixed>(field_number: u32, vec: &[V]) -> u64 {
    if vec.is_empty() {
        0
    } else {
        let data_size = vec_packed_fixed_data_size::<V>(vec);
        tag_size(field_number) + data_size.len_varint() + data_size
    }
}
<commit_msg>Mark more functions inline<commit_after>use crate::rt::compute_raw_varint32_size;
use crate::rt::tag_size;
use crate::rt::ProtobufFixed;
use crate::rt::ProtobufVarint;
use crate::rt::ProtobufVarintZigzag;
use crate::Enum;
use crate::EnumOrUnknown;

/// Size of serialized repeated packed field, excluding length and tag.
pub fn vec_packed_varint_data_size<T: ProtobufVarint>(vec: &[T]) -> u64 {
    vec.iter()
        .map(|v| v.len_varint() as u64)
        .fold(0, |a, i| a + i)
}

/// Size of serialized repeated packed field, excluding length and tag.
pub fn vec_packed_varint_zigzag_data_size<T: ProtobufVarintZigzag>(vec: &[T]) -> u64 {
    vec.iter()
        .map(|v| v.len_varint_zigzag())
        .fold(0, |a, i| a + i)
}

/// Size of serialized repeated packed enum field, excluding length and tag.
pub fn vec_packed_enum_or_unknown_data_size<E: Enum>(vec: &[EnumOrUnknown<E>]) -> u64 {
    vec.iter()
        .map(|e| compute_raw_varint32_size(e.value() as u32))
        .fold(0, |a, i| a + i)
}

/// Size of serialized data with length prefix and tag
#[inline]
pub fn vec_packed_varint_size<T: ProtobufVarint>(field_number: u32, vec: &[T]) -> u64 {
    if vec.is_empty() {
        0
    } else {
        let data_size = vec_packed_varint_data_size(vec);
        tag_size(field_number) + data_size.len_varint() + data_size
    }
}

/// Size of serialized data with length prefix and tag
#[inline]
pub fn vec_packed_varint_zigzag_size<T: ProtobufVarintZigzag>(field_number: u32, vec: &[T]) -> u64 {
    if vec.is_empty() {
        0
    } else {
        let data_size = vec_packed_varint_zigzag_data_size(vec);
        tag_size(field_number) + data_size.len_varint() + data_size
    }
}

/// Size of serialized data with length prefix and tag
#[inline]
pub fn vec_packed_enum_or_unknown_size<E: Enum>(
    field_number: u32,
    vec: &[EnumOrUnknown<E>],
) -> u64 {
    if vec.is_empty() {
        0
    } else {
        let data_size = vec_packed_enum_or_unknown_data_size(vec);
        tag_size(field_number) + data_size.len_varint() + data_size
    }
}

/// Compute data size of fixed encoding of repeated field data.
pub(crate) fn vec_packed_fixed_data_size<V: ProtobufFixed>(vec: &[V]) -> u64 {
    (vec.len() as u64) * (V::LEN as u64)
}

/// Compute field size (data plus header) of fixed encoding of repeated field.
#[inline]
pub fn vec_packed_fixed_size<V: ProtobufFixed>(field_number: u32, vec: &[V]) -> u64 {
    if vec.is_empty() {
        0
    } else {
        let data_size = vec_packed_fixed_data_size::<V>(vec);
        tag_size(field_number) + data_size.len_varint() + data_size
    }
}
<|endoftext|>