<commit_before>#![cfg_attr(not(feature = "gtk_3_10"), allow(unused_variables, unused_mut))]

extern crate glib;
extern crate gdk;
extern crate gio;
extern crate gtk;

use gio::prelude::*;
use gtk::prelude::*;
use gtk::{
    self, AboutDialog, ApplicationWindow, AppChooserDialog, Builder, Button, Dialog, Entry,
    FileChooserAction, FileChooserDialog, FontChooserDialog, Scale, SpinButton,
    RecentChooserDialog, ResponseType, Spinner, Switch, Window,
};

use std::env::args;

// make moving clones into closures more convenient
macro_rules! clone {
    (@param _) => ( _ );
    (@param $x:ident) => ( $x );
    ($($n:ident),+ => move || $body:expr) => (
        {
            $( let $n = $n.clone(); )+
                move || $body
        }
    );
    ($($n:ident),+ => move |$($p:tt),+| $body:expr) => (
        {
            $( let $n = $n.clone(); )+
                move |$(clone!(@param $p),)+| $body
        }
    );
}

// upgrade weak reference or return
#[macro_export]
macro_rules! upgrade_weak {
    ($x:ident, $r:expr) => {{
        match $x.upgrade() {
            Some(o) => o,
            None => return $r,
        }
    }};
    ($x:ident) => {
        upgrade_weak!($x, ())
    };
}

fn about_clicked(button: &Button, dialog: &AboutDialog) {
    if let Some(window) = button.get_toplevel().and_then(|w| w.downcast::<Window>().ok()) {
        dialog.set_transient_for(Some(&window));
    }

    println!("Authors: {:?}", dialog.get_authors());
    println!("Artists: {:?}", dialog.get_artists());
    println!("Documenters: {:?}", dialog.get_documenters());

    // Since we only have once instance of this object with Glade, we only show/hide it.
    dialog.show();
    dialog.run();
    dialog.hide();
}

fn build_ui(application: &gtk::Application) {
    println!("Major: {}, Minor: {}", gtk::get_major_version(), gtk::get_minor_version());
    let glade_src = include_str!("gtktest.glade");
    let builder = Builder::new_from_string(glade_src);

    let spinner: Spinner = builder.get_object("spinner").expect("Couldn't get spinner");
    spinner.start();

    let scale: Scale = builder.get_object("scale").expect("Couldn't get scale");
    scale.connect_format_value(|scale, value| {
        let digits = scale.get_digits() as usize;
        format!("<{:.*}>", digits, value)
    });

    let spin_button: SpinButton = builder.get_object("spin_button")
                                             .expect("Couldn't get spin_button");
    spin_button.connect_input(|spin_button| {
        let text = spin_button.get_text().expect("Couldn't get text from spin_button");
        println!("spin_button_input: \"{}\"", text);
        match text.parse::<f64>() {
            Ok(value) if value >= 90. => {
                println!("circular right");
                Some(Ok(10.))
            }
            Ok(value) if value <= 10. => {
                println!("circular left");
                Some(Ok(90.))
            }
            Ok(value) => Some(Ok(value)),
            Err(_) => Some(Err(())),
        }
    });

    let window: ApplicationWindow = builder.get_object("window").expect("Couldn't get window");
    window.set_application(application);

    let window_weak = window.downgrade();

    let button: Button = builder.get_object("button").expect("Couldn't get button");
    let entry: Entry = builder.get_object("entry").expect("Couldn't get entry");

    let entry_weak = entry.downgrade();
    button.connect_clicked(clone!(window_weak, entry_weak => move |_| {
        let window = upgrade_weak!(window_weak);
        let entry = upgrade_weak!(entry_weak);

        let dialog = Dialog::new_with_buttons(Some("Hello!"),
                                              Some(&window),
                                              gtk::DialogFlags::MODAL,
                                              &[("No", ResponseType::No),
                                                ("Yes", ResponseType::Yes),
                                                ("Custom", ResponseType::Other(0))]);

        let ret = dialog.run();

        dialog.destroy();

        entry.set_text(&format!("Clicked {}", ret));
    }));

    let button_font: Button = builder.get_object("button_font")
        .expect("Couldn't get button_font");
    button_font.connect_clicked(clone!(window_weak => move |_| {
            let window = upgrade_weak!(window_weak);

        let dialog = FontChooserDialog::new(Some("Font chooser test"), Some(&window));

        dialog.run();
        dialog.destroy();
    }));

    let button_recent: Button = builder.get_object("button_recent")
        .expect("Couldn't get button_recent");
    button_recent.connect_clicked(clone!(window_weak => move |_| {
        let window = upgrade_weak!(window_weak);

        let dialog = RecentChooserDialog::new(Some("Recent chooser test"), Some(&window));
        dialog.add_buttons(&[
            ("Ok", ResponseType::Ok.into()),
            ("Cancel", ResponseType::Cancel.into())
        ]);

        dialog.run();
        dialog.destroy();
    }));

    let file_button: Button = builder.get_object("file_button")
        .expect("Couldn't get file_button");
    file_button.connect_clicked(clone!(window_weak => move |_| {
        let window = upgrade_weak!(window_weak);

        //entry.set_text("Clicked!");
        let dialog = FileChooserDialog::new(Some("Choose a file"), Some(&window),
                                            FileChooserAction::Open);
        dialog.add_buttons(&[
            ("Open", ResponseType::Ok.into()),
            ("Cancel", ResponseType::Cancel.into())
        ]);

        dialog.set_select_multiple(true);
        dialog.run();
        let files = dialog.get_filenames();
        dialog.destroy();

        println!("Files: {:?}", files);
    }));

    let app_button: Button = builder.get_object("app_button").expect("Couldn't get app_button");
    app_button.connect_clicked(clone!(window_weak => move |_| {
        let window = upgrade_weak!(window_weak);

        //entry.set_text("Clicked!");
        let dialog = AppChooserDialog::new_for_content_type(Some(&window), gtk::DialogFlags::MODAL,
                                                            "sh");

        dialog.run();
        dialog.destroy();
    }));

    let switch: Switch = builder.get_object("switch").expect("Couldn't get switch");
    switch.connect_changed_active(clone!(entry_weak => move |switch| {
        let entry = upgrade_weak!(entry_weak);

        if switch.get_active() {
            entry.set_text("Switch On");
        } else {
            entry.set_text("Switch Off");
        }
    }));

    let button_about: Button = builder.get_object("button_about")
        .expect("Couldn't get button_about");
    let dialog: AboutDialog = builder.get_object("dialog").expect("Couldn't get dialog");
    button_about.connect_clicked(move |x| {
        about_clicked(x, &dialog)
    });

    window.connect_key_press_event(clone!(entry_weak => move |_, key| {
        let entry = upgrade_weak!(entry_weak, Inhibit(false));

        let keyval = key.get_keyval();
        let keystate = key.get_state();

        println!("key pressed: {} / {:?}", keyval, keystate);
        println!("text: {}", entry.get_text().expect("Couldn't get text from entry"));

        if keystate.intersects(gdk::ModifierType::CONTROL_MASK) {
            println!("You pressed Ctrl!");
        }

        Inhibit(false)
    }));

    window.show_all();
}

fn main() {
    let application = gtk::Application::new("com.github.gtk-rs.examples.gtktest",
                                            Default::default())
        .expect("Initialization failed...");

    application.connect_activate(|app| {
        build_ui(app);
    });

    application.run(&args().collect::<Vec<_>>());
}
<commit_msg>Remove unneeded use<commit_after>#![cfg_attr(not(feature = "gtk_3_10"), allow(unused_variables, unused_mut))]

extern crate glib;
extern crate gdk;
extern crate gio;
extern crate gtk;

use gio::prelude::*;
use gtk::prelude::*;
use gtk::{
    AboutDialog, ApplicationWindow, AppChooserDialog, Builder, Button, Dialog, Entry,
    FileChooserAction, FileChooserDialog, FontChooserDialog, Scale, SpinButton,
    RecentChooserDialog, ResponseType, Spinner, Switch, Window,
};

use std::env::args;

// make moving clones into closures more convenient
macro_rules! clone {
    (@param _) => ( _ );
    (@param $x:ident) => ( $x );
    ($($n:ident),+ => move || $body:expr) => (
        {
            $( let $n = $n.clone(); )+
                move || $body
        }
    );
    ($($n:ident),+ => move |$($p:tt),+| $body:expr) => (
        {
            $( let $n = $n.clone(); )+
                move |$(clone!(@param $p),)+| $body
        }
    );
}

// upgrade weak reference or return
#[macro_export]
macro_rules! upgrade_weak {
    ($x:ident, $r:expr) => {{
        match $x.upgrade() {
            Some(o) => o,
            None => return $r,
        }
    }};
    ($x:ident) => {
        upgrade_weak!($x, ())
    };
}

fn about_clicked(button: &Button, dialog: &AboutDialog) {
    if let Some(window) = button.get_toplevel().and_then(|w| w.downcast::<Window>().ok()) {
        dialog.set_transient_for(Some(&window));
    }

    println!("Authors: {:?}", dialog.get_authors());
    println!("Artists: {:?}", dialog.get_artists());
    println!("Documenters: {:?}", dialog.get_documenters());

    // Since we only have once instance of this object with Glade, we only show/hide it.
    dialog.show();
    dialog.run();
    dialog.hide();
}

fn build_ui(application: &gtk::Application) {
    println!("Major: {}, Minor: {}", gtk::get_major_version(), gtk::get_minor_version());
    let glade_src = include_str!("gtktest.glade");
    let builder = Builder::new_from_string(glade_src);

    let spinner: Spinner = builder.get_object("spinner").expect("Couldn't get spinner");
    spinner.start();

    let scale: Scale = builder.get_object("scale").expect("Couldn't get scale");
    scale.connect_format_value(|scale, value| {
        let digits = scale.get_digits() as usize;
        format!("<{:.*}>", digits, value)
    });

    let spin_button: SpinButton = builder.get_object("spin_button")
                                             .expect("Couldn't get spin_button");
    spin_button.connect_input(|spin_button| {
        let text = spin_button.get_text().expect("Couldn't get text from spin_button");
        println!("spin_button_input: \"{}\"", text);
        match text.parse::<f64>() {
            Ok(value) if value >= 90. => {
                println!("circular right");
                Some(Ok(10.))
            }
            Ok(value) if value <= 10. => {
                println!("circular left");
                Some(Ok(90.))
            }
            Ok(value) => Some(Ok(value)),
            Err(_) => Some(Err(())),
        }
    });

    let window: ApplicationWindow = builder.get_object("window").expect("Couldn't get window");
    window.set_application(application);

    let window_weak = window.downgrade();

    let button: Button = builder.get_object("button").expect("Couldn't get button");
    let entry: Entry = builder.get_object("entry").expect("Couldn't get entry");

    let entry_weak = entry.downgrade();
    button.connect_clicked(clone!(window_weak, entry_weak => move |_| {
        let window = upgrade_weak!(window_weak);
        let entry = upgrade_weak!(entry_weak);

        let dialog = Dialog::new_with_buttons(Some("Hello!"),
                                              Some(&window),
                                              gtk::DialogFlags::MODAL,
                                              &[("No", ResponseType::No),
                                                ("Yes", ResponseType::Yes),
                                                ("Custom", ResponseType::Other(0))]);

        let ret = dialog.run();

        dialog.destroy();

        entry.set_text(&format!("Clicked {}", ret));
    }));

    let button_font: Button = builder.get_object("button_font")
        .expect("Couldn't get button_font");
    button_font.connect_clicked(clone!(window_weak => move |_| {
            let window = upgrade_weak!(window_weak);

        let dialog = FontChooserDialog::new(Some("Font chooser test"), Some(&window));

        dialog.run();
        dialog.destroy();
    }));

    let button_recent: Button = builder.get_object("button_recent")
        .expect("Couldn't get button_recent");
    button_recent.connect_clicked(clone!(window_weak => move |_| {
        let window = upgrade_weak!(window_weak);

        let dialog = RecentChooserDialog::new(Some("Recent chooser test"), Some(&window));
        dialog.add_buttons(&[
            ("Ok", ResponseType::Ok.into()),
            ("Cancel", ResponseType::Cancel.into())
        ]);

        dialog.run();
        dialog.destroy();
    }));

    let file_button: Button = builder.get_object("file_button")
        .expect("Couldn't get file_button");
    file_button.connect_clicked(clone!(window_weak => move |_| {
        let window = upgrade_weak!(window_weak);

        //entry.set_text("Clicked!");
        let dialog = FileChooserDialog::new(Some("Choose a file"), Some(&window),
                                            FileChooserAction::Open);
        dialog.add_buttons(&[
            ("Open", ResponseType::Ok.into()),
            ("Cancel", ResponseType::Cancel.into())
        ]);

        dialog.set_select_multiple(true);
        dialog.run();
        let files = dialog.get_filenames();
        dialog.destroy();

        println!("Files: {:?}", files);
    }));

    let app_button: Button = builder.get_object("app_button").expect("Couldn't get app_button");
    app_button.connect_clicked(clone!(window_weak => move |_| {
        let window = upgrade_weak!(window_weak);

        //entry.set_text("Clicked!");
        let dialog = AppChooserDialog::new_for_content_type(Some(&window), gtk::DialogFlags::MODAL,
                                                            "sh");

        dialog.run();
        dialog.destroy();
    }));

    let switch: Switch = builder.get_object("switch").expect("Couldn't get switch");
    switch.connect_changed_active(clone!(entry_weak => move |switch| {
        let entry = upgrade_weak!(entry_weak);

        if switch.get_active() {
            entry.set_text("Switch On");
        } else {
            entry.set_text("Switch Off");
        }
    }));

    let button_about: Button = builder.get_object("button_about")
        .expect("Couldn't get button_about");
    let dialog: AboutDialog = builder.get_object("dialog").expect("Couldn't get dialog");
    button_about.connect_clicked(move |x| {
        about_clicked(x, &dialog)
    });

    window.connect_key_press_event(clone!(entry_weak => move |_, key| {
        let entry = upgrade_weak!(entry_weak, Inhibit(false));

        let keyval = key.get_keyval();
        let keystate = key.get_state();

        println!("key pressed: {} / {:?}", keyval, keystate);
        println!("text: {}", entry.get_text().expect("Couldn't get text from entry"));

        if keystate.intersects(gdk::ModifierType::CONTROL_MASK) {
            println!("You pressed Ctrl!");
        }

        Inhibit(false)
    }));

    window.show_all();
}

fn main() {
    let application = gtk::Application::new("com.github.gtk-rs.examples.gtktest",
                                            Default::default())
        .expect("Initialization failed...");

    application.connect_activate(|app| {
        build_ui(app);
    });

    application.run(&args().collect::<Vec<_>>());
}
<|endoftext|>


<commit_before>extern crate graphite;

#[macro_use]
extern crate log;
extern crate env_logger;
extern crate rustc_serialize;
extern crate docopt;
extern crate time;

use docopt::Docopt;
use graphite::whisper::{ WhisperFile, Point };
use graphite::whisper::schema::Schema;

static USAGE: &'static str = "
Whisper is the fast file manipulator

Usage:
    whisper info <file>
    whisper dump <file>
    whisper update <file> <timestamp> <value>
    whisper mark <file> <value>
    whisper thrash <file> <value> <times>
    whisper create <file> <timespec>...

Options:
    --xff <x_files_factor>
    --aggregation_method <method>
";

#[derive(RustcDecodable, Debug)]
struct Args {
    cmd_info: bool,
    cmd_dump: bool,
    cmd_update: bool,
    cmd_mark: bool,
    cmd_thrash: bool,
    cmd_create: bool,

    arg_file: String,
    arg_timestamp: String,
    arg_value: String,
    arg_times: String,

    arg_timespec: Vec<String>
}

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

    let arg_file = args.arg_file.clone();
    let path = unsafe {
        arg_file.slice_unchecked(0, args.arg_file.len())
    };

    let current_time = time::get_time().sec as u64;

    if args.cmd_info {
        cmd_info(path);
    } else if args.cmd_dump {
        cmd_dump(path);
    } else if args.cmd_update {
        cmd_update(args, path, current_time);
    } else if args.cmd_mark {
        cmd_mark(args, path, current_time);
    } else if args.cmd_thrash {
        cmd_thrash(args, path, current_time);
    } else if args.cmd_create {
        cmd_create(args, path);
    } else {
        println!("Must specify command.");
    }
}

fn cmd_info(path: &str) {
    let file_open = WhisperFile::open(path);
    match file_open {
        Ok(whisper_file) => println!("{}", whisper_file),
        Err(why) => {
            println!("could create whisper file: {:?}", why)
        }
    }
}

fn cmd_dump(path: &str) {
    let file_open = WhisperFile::open(path);
    match file_open {
        Ok(whisper_file) => println!("{:?}", whisper_file),
        Err(why) => {
            println!("could create whisper file: {:?}", why)
        }
    }
}

fn cmd_update(args: Args, path: &str, current_time: u64) {
    let mut file = WhisperFile::open(path).unwrap();
    let point = Point{
        timestamp: args.arg_timestamp.parse::<u64>().unwrap(),
        value: args.arg_value.parse::<f64>().unwrap()
    };
    debug!("Updating TS: {} with value: {}", point.timestamp, point.value);

    file.write(current_time, point);
}

fn cmd_mark(args: Args, path: &str, current_time: u64) {
    let mut file = WhisperFile::open(path).unwrap();
    let point = Point{
        timestamp: current_time,
        value: args.arg_value.parse::<f64>().unwrap()
    };

    file.write(current_time, point);
}

fn cmd_thrash(args: Args, path: &str, current_time: u64) {
    let times = args.arg_times.parse::<u64>().unwrap();
    let mut file = WhisperFile::open(path).unwrap();
    for index in 1..times {
        let point = Point{
            timestamp: current_time+index,
            value: args.arg_value.parse::<f64>().unwrap()
        };

        file.write(current_time+index, point);
    }
}

fn cmd_create(args: Args, path: &str) {
    let schema = Schema::new_from_retention_specs(args.arg_timespec);
    let new_result = WhisperFile::new(path, schema);
    match new_result {
        Ok(whisper_file) => println!("Success! {:?}", whisper_file),
        Err(why) => println!("Failed: {:?}", why)
    }
}
<commit_msg>Don't print out all points in file from CLI create<commit_after>extern crate graphite;

#[macro_use]
extern crate log;
extern crate env_logger;
extern crate rustc_serialize;
extern crate docopt;
extern crate time;

use docopt::Docopt;
use graphite::whisper::{ WhisperFile, Point };
use graphite::whisper::schema::Schema;

static USAGE: &'static str = "
Whisper is the fast file manipulator

Usage:
    whisper info <file>
    whisper dump <file>
    whisper update <file> <timestamp> <value>
    whisper mark <file> <value>
    whisper thrash <file> <value> <times>
    whisper create <file> <timespec>...

Options:
    --xff <x_files_factor>
    --aggregation_method <method>
";

#[derive(RustcDecodable, Debug)]
struct Args {
    cmd_info: bool,
    cmd_dump: bool,
    cmd_update: bool,
    cmd_mark: bool,
    cmd_thrash: bool,
    cmd_create: bool,

    arg_file: String,
    arg_timestamp: String,
    arg_value: String,
    arg_times: String,

    arg_timespec: Vec<String>
}

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

    let arg_file = args.arg_file.clone();
    let path = unsafe {
        arg_file.slice_unchecked(0, args.arg_file.len())
    };

    let current_time = time::get_time().sec as u64;

    if args.cmd_info {
        cmd_info(path);
    } else if args.cmd_dump {
        cmd_dump(path);
    } else if args.cmd_update {
        cmd_update(args, path, current_time);
    } else if args.cmd_mark {
        cmd_mark(args, path, current_time);
    } else if args.cmd_thrash {
        cmd_thrash(args, path, current_time);
    } else if args.cmd_create {
        cmd_create(args, path);
    } else {
        println!("Must specify command.");
    }
}

fn cmd_info(path: &str) {
    let file_open = WhisperFile::open(path);
    match file_open {
        Ok(whisper_file) => println!("{}", whisper_file),
        Err(why) => {
            println!("could create whisper file: {:?}", why)
        }
    }
}

fn cmd_dump(path: &str) {
    let file_open = WhisperFile::open(path);
    match file_open {
        Ok(whisper_file) => println!("{:?}", whisper_file),
        Err(why) => {
            println!("could create whisper file: {:?}", why)
        }
    }
}

fn cmd_update(args: Args, path: &str, current_time: u64) {
    let mut file = WhisperFile::open(path).unwrap();
    let point = Point{
        timestamp: args.arg_timestamp.parse::<u64>().unwrap(),
        value: args.arg_value.parse::<f64>().unwrap()
    };
    debug!("Updating TS: {} with value: {}", point.timestamp, point.value);

    file.write(current_time, point);
}

fn cmd_mark(args: Args, path: &str, current_time: u64) {
    let mut file = WhisperFile::open(path).unwrap();
    let point = Point{
        timestamp: current_time,
        value: args.arg_value.parse::<f64>().unwrap()
    };

    file.write(current_time, point);
}

fn cmd_thrash(args: Args, path: &str, current_time: u64) {
    let times = args.arg_times.parse::<u64>().unwrap();
    let mut file = WhisperFile::open(path).unwrap();
    for index in 1..times {
        let point = Point{
            timestamp: current_time+index,
            value: args.arg_value.parse::<f64>().unwrap()
        };

        file.write(current_time+index, point);
    }
}

fn cmd_create(args: Args, path: &str) {
    let schema = Schema::new_from_retention_specs(args.arg_timespec);
    let new_result = WhisperFile::new(path, schema);
    match new_result {
        Ok(whisper_file) => println!("Success! {}", whisper_file),
        Err(why) => println!("Failed: {:?}", why)
    }
}
<|endoftext|>


<commit_before>#[macro_use] extern crate match_any;

#[test]
fn empty() {
    let a: Box<std::any::Any> = Box::new(10);
    println!("{:?}", a);

    match_any!(a =>
        x: i32 => {
            assert_eq!(*x, 10);
        }
    );
}

// TODO: Add.
// #[bench]
<commit_msg>make_any<commit_after>#[macro_use] extern crate match_any;

use std::any::Any;

fn make_any<T: Any>(value: T) -> Box<Any> {
    Box::new(value)
}

#[test]
fn empty() {
    match_any!(make_any(10) =>
        x: i32 => {
            assert_eq!(*x, 10);
        }
    );
}

// TODO: Add.
// #[bench]
<|endoftext|>


<commit_before>#[cfg(feature = "lazy-blob")]
compile_error!("Tests must be run without lazy blobs.");

use libtest_mimic::{run_tests, Arguments, Outcome, Test};
use std::error::Error;
use std::fs::{read_dir, read_to_string};
use std::path::Path;
use wasmbin::io::{Decode, Encode};
use wasmbin::module::Module;
use wast::parser::{parse, ParseBuffer};
use wast::Wast;

const IGNORED_ERRORS: &[&str] = &[
    // We don't perform cross-section analysis.
    "function and code section have inconsistent lengths",
    // This error is actually from a test that checks for duplicate section.
    // Same as above, we don't perform cross-section analysis.
    "junk after last section",
    // We allow non-zero table and memory IDs already.
    "zero flag expected",
];

struct WasmTest {
    module: Vec<u8>,
    expect_result: Result<(), String>,
}

fn read_tests(path: &Path, dest: &mut Vec<Test<WasmTest>>) -> Result<(), Box<dyn Error>> {
    let src = read_to_string(path)?;
    let set_err_path_text = |mut err: wast::Error| {
        err.set_path(path);
        err.set_text(&src);
        err
    };
    let buf = ParseBuffer::new(&src).map_err(&set_err_path_text)?;
    let wast = parse::<Wast>(&buf).map_err(&set_err_path_text)?;
    for directive in wast.directives {
        let (span, mut module, expect_result) = match directive {
            // Expect errors for assert_malformed on binary or AST modules.
            wast::WastDirective::AssertMalformed {
                span,
                module: wast::QuoteModule::Module(module),
                message,
            } => (span, module, Err(message)),
            // Expect successful parsing for regular AST modules.
            wast::WastDirective::Module(module) => (module.span, module, Ok(())),
            // Counter-intuitively, expect successful parsing for modules that are supposed
            // to error out at runtime or linking stage, too.
            wast::WastDirective::AssertInvalid { span, module, .. }
            | wast::WastDirective::AssertUnlinkable { span, module, .. } => (span, module, Ok(())),
            _ => {
                // Skipping interpreted
                continue;
            }
        };
        let (line, col) = span.linecol_in(&src);
        dest.push(Test {
            name: format!("{}:{}:{}", path.display(), line + 1, col + 1),
            kind: String::default(),
            is_ignored: match expect_result {
                Ok(()) => false,
                Err(err) => IGNORED_ERRORS.contains(&err),
            },
            is_bench: false,
            data: WasmTest {
                module: module.encode()?,
                expect_result: expect_result.map_err(|err| err.to_owned()),
            },
        });
    }
    Ok(())
}

fn run_test(test: &WasmTest) -> Result<(), Box<dyn Error>> {
    let module = match (
        Module::decode(&mut test.module.as_slice()),
        &test.expect_result,
    ) {
        (Ok(_), Err(err)) => {
            return Err(format!(
                "Expected an invalid module definition with an error: {}",
                err
            )
            .into());
        }
        (Err(err), Ok(())) => {
            return Err(format!(
                "Expected a valid module definition, but got an error:\n{:#}",
                err
            )
            .into());
        }
        (Ok(module), Ok(())) => module,
        (Err(_), Err(_)) => return Ok(()),
    };
    let mut out = Vec::new();
    module.encode(&mut out)?;
    if out != test.module {
        // In the rare case that binary representation doesn't match, it
        // might be because the test uses longer LEB128 form than
        // required. Verify that at least decoding it back produces the
        // same module.
        let module2 = Module::decode(&mut out.as_slice())?;
        if module != module2 {
            return Err(format!(
                "Roundtrip mismatch. Old: {:#?}\nNew: {:#?}",
                module, module2
            )
            .into());
        }
    }
    Ok(())
}

fn main() {
    let mut tests = Vec::new();
    read_dir(Path::new("tests").join("testsuite"))
        .expect("could not read the testsuite directory")
        .map(|file| {
            file.expect("could not iterate over the testsuite directory")
                .path()
        })
        .filter(|path| path.extension().map_or(false, |ext| ext == "wast"))
        .for_each(|path| {
            read_tests(&path, &mut tests).unwrap_or_else(|err| {
                // If an error comes from the Wabt, ignore for now - most likely it uses a new feature we don't support yet.
                panic!("Could not read test {}: {}", path.display(), err);
            });
        });
    assert!(
        !tests.is_empty(),
        "Couldn't find any tests. Did you run `git submodule update --init`?"
    );
    run_tests(&Arguments::from_args(), tests, |test| {
        match run_test(&test.data) {
            Ok(()) => Outcome::Passed,
            Err(err) => Outcome::Failed {
                msg: Some(err.to_string()),
            },
        }
    })
    .exit()
}
<commit_msg>Allow but ignore lazy-blob errors in tests<commit_after>use libtest_mimic::{run_tests, Arguments, Outcome, Test};
use std::error::Error;
use std::fs::{read_dir, read_to_string};
use std::path::Path;
use wasmbin::io::{Decode, Encode};
use wasmbin::module::Module;
use wast::parser::{parse, ParseBuffer};
use wast::Wast;

const IGNORED_ERRORS: &[&str] = &[
    // We don't perform cross-section analysis.
    "function and code section have inconsistent lengths",
    // This error is actually from a test that checks for duplicate section.
    // Same as above, we don't perform cross-section analysis.
    "junk after last section",
    // We allow non-zero table and memory IDs already.
    "zero flag expected",
];

struct WasmTest {
    module: Vec<u8>,
    expect_result: Result<(), String>,
}

fn read_tests(path: &Path, dest: &mut Vec<Test<WasmTest>>) -> Result<(), Box<dyn Error>> {
    let src = read_to_string(path)?;
    let set_err_path_text = |mut err: wast::Error| {
        err.set_path(path);
        err.set_text(&src);
        err
    };
    let buf = ParseBuffer::new(&src).map_err(&set_err_path_text)?;
    let wast = parse::<Wast>(&buf).map_err(&set_err_path_text)?;
    for directive in wast.directives {
        let (span, mut module, expect_result) = match directive {
            // Expect errors for assert_malformed on binary or AST modules.
            wast::WastDirective::AssertMalformed {
                span,
                module: wast::QuoteModule::Module(module),
                message,
            } => (span, module, Err(message)),
            // Expect successful parsing for regular AST modules.
            wast::WastDirective::Module(module) => (module.span, module, Ok(())),
            // Counter-intuitively, expect successful parsing for modules that are supposed
            // to error out at runtime or linking stage, too.
            wast::WastDirective::AssertInvalid { span, module, .. }
            | wast::WastDirective::AssertUnlinkable { span, module, .. } => (span, module, Ok(())),
            _ => {
                // Skipping interpreted
                continue;
            }
        };
        let (line, col) = span.linecol_in(&src);
        dest.push(Test {
            name: format!("{}:{}:{}", path.display(), line + 1, col + 1),
            kind: String::default(),
            is_ignored: match expect_result {
                Ok(()) => false,
                Err(err) => cfg!(feature = "lazy-blob") || IGNORED_ERRORS.contains(&err),
            },
            is_bench: false,
            data: WasmTest {
                module: module.encode()?,
                expect_result: expect_result.map_err(|err| err.to_owned()),
            },
        });
    }
    Ok(())
}

fn run_test(test: &WasmTest) -> Result<(), Box<dyn Error>> {
    let module = match (
        Module::decode(&mut test.module.as_slice()),
        &test.expect_result,
    ) {
        (Ok(_), Err(err)) => {
            return Err(format!(
                "Expected an invalid module definition with an error: {}",
                err
            )
            .into());
        }
        (Err(err), Ok(())) => {
            return Err(format!(
                "Expected a valid module definition, but got an error:\n{:#}",
                err
            )
            .into());
        }
        (Ok(module), Ok(())) => module,
        (Err(_), Err(_)) => return Ok(()),
    };
    let mut out = Vec::new();
    module.encode(&mut out)?;
    if out != test.module {
        // In the rare case that binary representation doesn't match, it
        // might be because the test uses longer LEB128 form than
        // required. Verify that at least decoding it back produces the
        // same module.
        let module2 = Module::decode(&mut out.as_slice())?;
        if module != module2 {
            return Err(format!(
                "Roundtrip mismatch. Old: {:#?}\nNew: {:#?}",
                module, module2
            )
            .into());
        }
    }
    Ok(())
}

fn main() {
    if cfg!(feature = "lazy-blob") {
        eprintln!("Warning: tests are being run in a lazy mode and will be incomplete.");
    }

    let mut tests = Vec::new();
    read_dir(Path::new("tests").join("testsuite"))
        .expect("could not read the testsuite directory")
        .map(|file| {
            file.expect("could not iterate over the testsuite directory")
                .path()
        })
        .filter(|path| path.extension().map_or(false, |ext| ext == "wast"))
        .for_each(|path| {
            read_tests(&path, &mut tests).unwrap_or_else(|err| {
                // If an error comes from the Wabt, ignore for now - most likely it uses a new feature we don't support yet.
                panic!("Could not read test {}: {}", path.display(), err);
            });
        });
    assert!(
        !tests.is_empty(),
        "Couldn't find any tests. Did you run `git submodule update --init`?"
    );
    run_tests(&Arguments::from_args(), tests, |test| {
        match run_test(&test.data) {
            Ok(()) => Outcome::Passed,
            Err(err) => Outcome::Failed {
                msg: Some(err.to_string()),
            },
        }
    })
    .exit()
}
<|endoftext|>


<commit_before>extern crate r2d2;
extern crate r2d2_sqlite;
extern crate rusqlite;

use std::sync::mpsc;
use std::thread;

use r2d2_sqlite::SQLiteConnectionManager;
use rusqlite::OpenFlags;

#[test]
fn test_basic() {
    let manager = SQLiteConnectionManager::new(
        "file:dummy.db?mode=memory&cache=shared",
        OpenFlags::SQLITE_OPEN_URI | OpenFlags::SQLITE_OPEN_CREATE | OpenFlags::SQLITE_OPEN_READ_WRITE,
    );
    let pool = r2d2::Pool::builder().max_size(2).build(manager).unwrap();

    let (s1, r1) = mpsc::channel();
    let (s2, r2) = mpsc::channel();

    let pool1 = pool.clone();
    let t1 = thread::spawn(move || {
        let conn = pool1.get().unwrap();
        s1.send(()).unwrap();
        r2.recv().unwrap();
        drop(conn);
    });

    let pool2 = pool.clone();
    let t2 = thread::spawn(move || {
        let conn = pool2.get().unwrap();
        s2.send(()).unwrap();
        r1.recv().unwrap();
        drop(conn);
    });

    t1.join().unwrap();
    t2.join().unwrap();

    pool.get().unwrap();
}

#[test]
fn test_is_valid() {
    let manager = SQLiteConnectionManager::new(
        "file:dummy.db?mode=memory&cache=shared",
        OpenFlags::SQLITE_OPEN_URI | OpenFlags::SQLITE_OPEN_CREATE | OpenFlags::SQLITE_OPEN_READ_WRITE,
    );
    let pool = r2d2::Pool::builder()
        .max_size(1)
        .test_on_check_out(true)
        .build(manager)
        .unwrap();

    pool.get().unwrap();
}
<commit_msg>Rustfmt<commit_after>extern crate r2d2;
extern crate r2d2_sqlite;
extern crate rusqlite;

use std::sync::mpsc;
use std::thread;

use r2d2_sqlite::SQLiteConnectionManager;
use rusqlite::OpenFlags;

#[test]
fn test_basic() {
    let manager = SQLiteConnectionManager::new(
        "file:dummy.db?mode=memory&cache=shared",
        OpenFlags::SQLITE_OPEN_URI | OpenFlags::SQLITE_OPEN_CREATE
            | OpenFlags::SQLITE_OPEN_READ_WRITE,
    );
    let pool = r2d2::Pool::builder().max_size(2).build(manager).unwrap();

    let (s1, r1) = mpsc::channel();
    let (s2, r2) = mpsc::channel();

    let pool1 = pool.clone();
    let t1 = thread::spawn(move || {
        let conn = pool1.get().unwrap();
        s1.send(()).unwrap();
        r2.recv().unwrap();
        drop(conn);
    });

    let pool2 = pool.clone();
    let t2 = thread::spawn(move || {
        let conn = pool2.get().unwrap();
        s2.send(()).unwrap();
        r1.recv().unwrap();
        drop(conn);
    });

    t1.join().unwrap();
    t2.join().unwrap();

    pool.get().unwrap();
}

#[test]
fn test_is_valid() {
    let manager = SQLiteConnectionManager::new(
        "file:dummy.db?mode=memory&cache=shared",
        OpenFlags::SQLITE_OPEN_URI | OpenFlags::SQLITE_OPEN_CREATE
            | OpenFlags::SQLITE_OPEN_READ_WRITE,
    );
    let pool = r2d2::Pool::builder()
        .max_size(1)
        .test_on_check_out(true)
        .build(manager)
        .unwrap();

    pool.get().unwrap();
}
<|endoftext|>


<commit_before>// Copyright 2014 The html5ever Project Developers. See the
// COPYRIGHT file at the top-level directory of this distribution.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use std::io;
use std::path::Path;

pub fn foreach_html5lib_test(
        src_dir: Path,
        subdir: &'static str,
        ext: &'static str,
        mk: |path_str: &str, file: io::File|) {
    let test_dir_path = src_dir.join_many(["html5lib-tests", subdir]);
    let test_files = io::fs::readdir(&test_dir_path).ok().expect("can't open dir");
    for path in test_files.into_iter() {
        let path_str = path.filename_str().unwrap();
        if path_str.ends_with(ext) {
            let file = io::File::open(&path).ok().expect("can't open file");
            mk(path_str, file);
        }
    }
}
<commit_msg>Improve failure messages in `tests/util.rs`<commit_after>// Copyright 2014 The html5ever Project Developers. See the
// COPYRIGHT file at the top-level directory of this distribution.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use std::io;
use std::path::Path;

pub fn foreach_html5lib_test(
        src_dir: Path,
        subdir: &'static str,
        ext: &'static str,
        mk: |path_str: &str, file: io::File|) {
    let test_dir_path = src_dir.join_many(["html5lib-tests", subdir]);
    let test_files = io::fs::readdir(&test_dir_path).unwrap();
    for path in test_files.into_iter() {
        let path_str = path.filename_str().unwrap();
        if path_str.ends_with(ext) {
            let file = io::File::open(&path).unwrap();
            mk(path_str, file);
        }
    }
}
<|endoftext|>


<commit_before>//! This crate contains a compiler plugin to generate Named Binary Tag format
//! serialization code for custom structs. It can be used as follows:
//!
//! ```ignore
//! #![feature(plugin, custom_derive)]
//! #![plugin(nbt_macros)]
//!
//! extern crate nbt;
//!
//! use nbt::serialize::{NbtFmt, to_writer};
//!
//! #[derive(NbtFmt)]
//! struct MyMob {
//!     name: String,
//!     health: i8
//! }
//!
//! fn main() {
//!     let mut bytes = Vec::new();
//!     let mob = MyMob { name: "Dr. Evil".to_string(), health: 240 };
//!
//!     to_writer(&mut bytes, mob).unwrap();
//! }
//! ```
//!
//! The custom `derive(NbtFmt)` will generate code equivalent to the following:
//!
//! ```ignore
//! impl NbtFmt for MyMob {
//!     fn to_bare_nbt<W>(&self, dst: &mut W) -> nbt::Result<()>
//!        where W: std::io::Write
//!     {
//!         try!(self.name.to_nbt(dst, "name"));
//!         try!(self.health.to_nbt(dst, "health"));
//!
//!         close_nbt(dst)
//!     }
//! }
//! ```
//!
//! Which will work so long as the fields of the struct have `NbtFmt`
//! implementations of their own.

#![feature(plugin_registrar, rustc_private, box_syntax)]

extern crate rustc;
extern crate syntax;

use syntax::ast;
use syntax::ast::{Expr, MetaItem, Mutability};
use syntax::attr::AttrMetaMethods;
use syntax::codemap::Span;
use syntax::ext::base::{Annotatable, ExtCtxt, MultiDecorator};
use syntax::ext::build::AstBuilder;
use syntax::ext::deriving::generic::*;
use syntax::ext::deriving::generic::ty::*;
use syntax::parse::token::{get_ident, intern, intern_and_get_ident, InternedString};
use syntax::ptr::P;

#[plugin_registrar]
#[doc(hidden)]
pub fn plugin_registrar(reg: &mut rustc::plugin::Registry) {
    reg.register_syntax_extension(intern("derive_NbtFmt"),
                                  MultiDecorator(box expand_derive_nbtfmt));
}

macro_rules! pathvec {
    ($($x:ident)::+) => (
        vec![ $( stringify!($x) ),+ ]
    )
}

macro_rules! path {
    ($($x:tt)*) => (
        Path::new( pathvec!( $($x)* ) )
    )
}

macro_rules! pathexpr {
    ($cx:ident, $span:ident, $($x:ident)::+) => (
        $cx.expr_path($cx.path_global($span,
            vec![ $( $cx.ident_of( stringify!($x) ) ),+ ]))
    )
}

/// Expands uses of `#[derive(NbtFmt)]` into `NbtFmt` implementations.
pub fn expand_derive_nbtfmt(cx: &mut ExtCtxt, span: Span, meta_item: &MetaItem,
                            item: &Annotatable,
                            push: &mut FnMut(Annotatable))
{
    // First, check that we're deriving for a struct.
    if let &Annotatable::Item(ref it) = item {
        match it.node {
            ast::Item_::ItemStruct(_, _) => (), // Allow structs only.
            ast::Item_::ItemEnum(_, _) => {
                cx.span_err(span, "`NbtFmt` cannot yet be derived for enums.");
                return;
            },
            _ => {
                cx.span_err(span, "#[derive(NbtFmt)] only allowed on structs.");
                return;
            }
        }
    } else {
        cx.span_err(span, "#[derive(NbtFmt)] only allowed on structs.");
        return;
    }

    let trait_def = TraitDef {
        span: span,
        attributes: Vec::new(),
        path: path!(nbt::serialize::NbtFmt),
        additional_bounds: Vec::new(),
        generics: LifetimeBounds::empty(),
        methods: vec![
            MethodDef {
                name: "to_bare_nbt",
                generics: LifetimeBounds {
                    lifetimes: Vec::new(),
                    // This adds a <__W: std::io::Writer> generic to the method.
                    bounds: vec![("__W", vec![path!(std::io::Write)])],
                },
                // Pass the immutable borrowed self argument, `&self`.
                explicit_self: borrowed_explicit_self(),
                // Pass a single argument of type `&mut __W`.
                args: vec![Ptr(box Literal(Path::new_local("__W")),
                           Borrowed(None, Mutability::MutMutable))],
                // Return a `Result<(), nbt::Error>`.
                ret_ty: Literal(Path {
                    path: pathvec!(std::result::Result),
                    lifetime: None,
                    params: vec![box Tuple(Vec::new()), box Literal(path!(nbt::Error))],
                    global: true }),
                attributes: Vec::new(), // FIXME: Benchmark adding #[inline].
                is_unsafe: false,
                combine_substructure: combine_substructure(box cs_to_bare_nbt),
            },
            MethodDef {
                name: "read_bare_nbt",
                generics: LifetimeBounds {
                    lifetimes: Vec::new(),
                    // This adds a <__R: std::io::Read> generic to the method.
                    bounds: vec![("__R", vec![path!(std::io::Read)])],
                },
                // No self argument.
                explicit_self: None,
                // Pass a single argument of type `&mut __R`.
                args: vec![Ptr(box Literal(Path::new_local("__R")),
                               Borrowed(None, Mutability::MutMutable))],
                // Return a `Result<Self, nbt::Error>`.
                ret_ty: Literal(Path {
                    path: pathvec!(std::result::Result),
                    lifetime: None,
                    params: vec![box Self_, box Literal(path!(nbt::Error))],
                    global: true }),
                attributes: Vec::new(), // FIXME: Benchmark adding #[inline].
                is_unsafe: false,
                combine_substructure: combine_substructure(box cs_read_bare_nbt)
            },
        ],
        associated_types: vec![(cx.ident_of("Into"), Self_)],
    };

    trait_def.expand(cx, meta_item, item, push)
}

fn cs_to_bare_nbt(cx: &mut ExtCtxt, trait_span: Span, substr: &Substructure) -> P<Expr> {
    // Retrieve the argument passed to the to_bare_nbt function, i.e. the
    // `dst: &mut __W` bit. Since the method is already defined, there's no
    // reason for this to fail, so we call `cx.span_bug` indicating a compiler
    // error.
    let dst_expr = match (substr.nonself_args.len(), substr.nonself_args.get(0)) {
        (1, Some(dst)) => dst,
        _ => cx.span_bug(trait_span, "incorrect number of method arguments in `derive(NbtFmt)`")
    };

    // Define a closure that iterates over the fields in the struct and
    // generates a statement akin to `try!(NbtFmt::to_nbt(self, field));`.
    let call_nbt_fmt = |span, struct_self, name| {

        // Create expressions for the path to the `to_nbt` method and `&self`.
        let nbt_fmt_path = pathexpr!(cx, span, nbt::serialize::NbtFmt::to_nbt);
        let self_arg = cx.expr_addr_of(span, struct_self);

        // Create a string literal expression for the field's identifier.
        let name_expr = cx.expr_str(span, name);

        // Create a call expression, using the function path (nbt_fmt_path)
        // and `&self, dst, "<field>"` as arguments.
        let fmt_call = cx.expr_call(span, nbt_fmt_path,
                                    vec!(self_arg, dst_expr.clone(), name_expr));

        // Wrap the call in a try! macro.
        let try_fmt_call = cx.expr_try(span, fmt_call);

        // Add a semicolon.
        cx.stmt_expr(try_fmt_call)
    };

    match *substr.fields {
        Struct(ref fields) => {
            // Unit structs are kind of irrelevant for NBT, so throw an error
            // if someone tries to derive(NbtFmt) over one.
            if fields.is_empty() {
                cx.span_err(trait_span, "`NbtFmt` has no meaning for unit structs.");
                return cx.expr_fail(trait_span, InternedString::new(""));
            }

            let mut stmts = Vec::with_capacity(fields.len());

            // Handle tuple structs, i.e. `struct Test(i8, i8, String);`
            // by using `"field0"`, `"field1"`, etc. as names.
            if fields[0].name.is_none() {
                for (i, field) in fields.iter().enumerate() {
                    // Just in case there is a compiler bug and we get an
                    // *named* field in the middle of a tuple struct, call `cx.bug`.
                    if let Some(_) = field.name {
                        cx.span_bug(trait_span, "named field in tuple struct")
                    }

                    // Make an interned "fieldX" string.
                    let name_ = intern_and_get_ident(&format!("field{}", i));

                    // Apply the closure on this named field.
                    stmts.push(call_nbt_fmt(field.span, field.self_.clone(), name_));
                }
            } else {
                for &FieldInfo { ref self_, span, name, attrs, .. } in fields {
                    // Just in case there is a compiler bug and we get an
                    // unnamed field in the middle of a struct, call `cx.bug`.
                    if let None = name {
                        cx.span_bug(trait_span, "unnamed field in named struct")
                    }

                    let mut name_ = get_ident(name.unwrap());

                    // Optionally change the name of the field when the
                    // #[nbt_field = "fieldX"] attribute is present on the item.
                    for ref attr in attrs {
                        if attr.check_name("nbt_field") {
                            if let Some(s) = attr.value_str() {
                                name_ = s;
                            } else {
                                cx.span_err(span, "`#[nbt_field]` requires a &str value.");
                                return cx.expr_fail(trait_span, InternedString::new(""));
                            }
                            break;
                        }
                    }

                    // Apply the closure on this named field.
                    stmts.push(call_nbt_fmt(span, self_.clone(), name_));
                }
            }

            // Creates a `close_nbt(dst)` expression to add to the end of
            // the block.
            let close_nbt_path = pathexpr!(cx, trait_span, nbt::serialize::close_nbt);
            let close = cx.expr_call(trait_span, close_nbt_path, vec![dst_expr.clone()]);

            cx.expr_block(cx.block(trait_span, stmts, Some(close)))
        },
        _ => cx.span_bug(trait_span, "impossible substructure in `#[derive(NbtFmt)]`")
    }
}

fn cs_read_bare_nbt(cx: &mut ExtCtxt, trait_span: Span, substr: &Substructure) -> P<Expr> {
    match *substr.fields {
        StaticStruct(_, _) => cx.expr_unreachable(trait_span),
        _ => cx.span_bug(trait_span, "impossible substructure in `#[derive(NbtFmt)]`")
    }
}
<commit_msg>Now checks for unit structs much earlier in the compiler plugin.<commit_after>//! This crate contains a compiler plugin to generate Named Binary Tag format
//! serialization code for custom structs. It can be used as follows:
//!
//! ```ignore
//! #![feature(plugin, custom_derive)]
//! #![plugin(nbt_macros)]
//!
//! extern crate nbt;
//!
//! use nbt::serialize::{NbtFmt, to_writer};
//!
//! #[derive(NbtFmt)]
//! struct MyMob {
//!     name: String,
//!     health: i8
//! }
//!
//! fn main() {
//!     let mut bytes = Vec::new();
//!     let mob = MyMob { name: "Dr. Evil".to_string(), health: 240 };
//!
//!     to_writer(&mut bytes, mob).unwrap();
//! }
//! ```
//!
//! The custom `derive(NbtFmt)` will generate code equivalent to the following:
//!
//! ```ignore
//! impl NbtFmt for MyMob {
//!     fn to_bare_nbt<W>(&self, dst: &mut W) -> nbt::Result<()>
//!        where W: std::io::Write
//!     {
//!         try!(self.name.to_nbt(dst, "name"));
//!         try!(self.health.to_nbt(dst, "health"));
//!
//!         close_nbt(dst)
//!     }
//! }
//! ```
//!
//! Which will work so long as the fields of the struct have `NbtFmt`
//! implementations of their own.

#![feature(plugin_registrar, rustc_private, box_syntax)]

extern crate rustc;
extern crate syntax;

use syntax::ast;
use syntax::ast::{Expr, MetaItem, Mutability};
use syntax::attr::AttrMetaMethods;
use syntax::codemap::Span;
use syntax::ext::base::{Annotatable, ExtCtxt, MultiDecorator};
use syntax::ext::build::AstBuilder;
use syntax::ext::deriving::generic::*;
use syntax::ext::deriving::generic::ty::*;
use syntax::parse::token::{get_ident, intern, intern_and_get_ident, InternedString};
use syntax::ptr::P;

#[plugin_registrar]
#[doc(hidden)]
pub fn plugin_registrar(reg: &mut rustc::plugin::Registry) {
    reg.register_syntax_extension(intern("derive_NbtFmt"),
                                  MultiDecorator(box expand_derive_nbtfmt));
}

macro_rules! pathvec {
    ($($x:ident)::+) => (
        vec![ $( stringify!($x) ),+ ]
    )
}

macro_rules! path {
    ($($x:tt)*) => (
        Path::new( pathvec!( $($x)* ) )
    )
}

macro_rules! pathexpr {
    ($cx:ident, $span:ident, $($x:ident)::+) => (
        $cx.expr_path($cx.path_global($span,
            vec![ $( $cx.ident_of( stringify!($x) ) ),+ ]))
    )
}

/// Expands uses of `#[derive(NbtFmt)]` into `NbtFmt` implementations.
pub fn expand_derive_nbtfmt(cx: &mut ExtCtxt, span: Span, meta_item: &MetaItem,
                            item: &Annotatable,
                            push: &mut FnMut(Annotatable))
{
    // First, check that we're deriving for a non-unit struct.
    if let &Annotatable::Item(ref it) = item {
        match it.node {
            ast::Item_::ItemStruct(ref def, _) => {
                if def.fields.is_empty() {
                    cx.span_err(span, "`NbtFmt` has no meaning for unit structs.");
                    return;
                }
            },
            ast::Item_::ItemEnum(_, _) => {
                cx.span_err(span, "`NbtFmt` cannot yet be derived for enums.");
                return;
            },
            _ => {
                cx.span_err(span, "#[derive(NbtFmt)] only allowed on structs.");
                return;
            }
        }
    } else {
        cx.span_err(span, "#[derive(NbtFmt)] only allowed on structs.");
        return;
    }

    let trait_def = TraitDef {
        span: span,
        attributes: Vec::new(),
        path: path!(nbt::serialize::NbtFmt),
        additional_bounds: Vec::new(),
        generics: LifetimeBounds::empty(),
        methods: vec![
            MethodDef {
                name: "to_bare_nbt",
                generics: LifetimeBounds {
                    lifetimes: Vec::new(),
                    // This adds a <__W: std::io::Writer> generic to the method.
                    bounds: vec![("__W", vec![path!(std::io::Write)])],
                },
                // Pass the immutable borrowed self argument, `&self`.
                explicit_self: borrowed_explicit_self(),
                // Pass a single argument of type `&mut __W`.
                args: vec![Ptr(box Literal(Path::new_local("__W")),
                           Borrowed(None, Mutability::MutMutable))],
                // Return a `Result<(), nbt::Error>`.
                ret_ty: Literal(Path {
                    path: pathvec!(std::result::Result),
                    lifetime: None,
                    params: vec![box Tuple(Vec::new()), box Literal(path!(nbt::Error))],
                    global: true }),
                attributes: Vec::new(), // FIXME: Benchmark adding #[inline].
                is_unsafe: false,
                combine_substructure: combine_substructure(box cs_to_bare_nbt),
            },
            MethodDef {
                name: "read_bare_nbt",
                generics: LifetimeBounds {
                    lifetimes: Vec::new(),
                    // This adds a <__R: std::io::Read> generic to the method.
                    bounds: vec![("__R", vec![path!(std::io::Read)])],
                },
                // No self argument.
                explicit_self: None,
                // Pass a single argument of type `&mut __R`.
                args: vec![Ptr(box Literal(Path::new_local("__R")),
                               Borrowed(None, Mutability::MutMutable))],
                // Return a `Result<Self, nbt::Error>`.
                ret_ty: Literal(Path {
                    path: pathvec!(std::result::Result),
                    lifetime: None,
                    params: vec![box Self_, box Literal(path!(nbt::Error))],
                    global: true }),
                attributes: Vec::new(), // FIXME: Benchmark adding #[inline].
                is_unsafe: false,
                combine_substructure: combine_substructure(box cs_read_bare_nbt)
            },
        ],
        associated_types: vec![(cx.ident_of("Into"), Self_)],
    };

    trait_def.expand(cx, meta_item, item, push)
}

fn cs_to_bare_nbt(cx: &mut ExtCtxt, trait_span: Span, substr: &Substructure) -> P<Expr> {
    // Retrieve the argument passed to the to_bare_nbt function, i.e. the
    // `dst: &mut __W` bit. Since the method is already defined, there's no
    // reason for this to fail, so we call `cx.span_bug` indicating a compiler
    // error.
    let dst_expr = match (substr.nonself_args.len(), substr.nonself_args.get(0)) {
        (1, Some(dst)) => dst,
        _ => cx.span_bug(trait_span, "incorrect number of method arguments in `derive(NbtFmt)`")
    };

    // Define a closure that iterates over the fields in the struct and
    // generates a statement akin to `try!(NbtFmt::to_nbt(self, field));`.
    let call_nbt_fmt = |span, struct_self, name| {

        // Create expressions for the path to the `to_nbt` method and `&self`.
        let nbt_fmt_path = pathexpr!(cx, span, nbt::serialize::NbtFmt::to_nbt);
        let self_arg = cx.expr_addr_of(span, struct_self);

        // Create a string literal expression for the field's identifier.
        let name_expr = cx.expr_str(span, name);

        // Create a call expression, using the function path (nbt_fmt_path)
        // and `&self, dst, "<field>"` as arguments.
        let fmt_call = cx.expr_call(span, nbt_fmt_path,
                                    vec!(self_arg, dst_expr.clone(), name_expr));

        // Wrap the call in a try! macro.
        let try_fmt_call = cx.expr_try(span, fmt_call);

        // Add a semicolon.
        cx.stmt_expr(try_fmt_call)
    };

    match *substr.fields {
        Struct(ref fields) => {
            let mut stmts = Vec::with_capacity(fields.len());

            // Handle tuple structs, i.e. `struct Test(i8, i8, String);`
            // by using `"field0"`, `"field1"`, etc. as names.
            if fields[0].name.is_none() {
                for (i, field) in fields.iter().enumerate() {
                    // Just in case there is a compiler bug and we get an
                    // *named* field in the middle of a tuple struct, call `cx.bug`.
                    if let Some(_) = field.name {
                        cx.span_bug(trait_span, "named field in tuple struct")
                    }

                    // Make an interned "fieldX" string.
                    let name_ = intern_and_get_ident(&format!("field{}", i));

                    // Apply the closure on this named field.
                    stmts.push(call_nbt_fmt(field.span, field.self_.clone(), name_));
                }
            } else {
                for &FieldInfo { ref self_, span, name, attrs, .. } in fields {
                    // Just in case there is a compiler bug and we get an
                    // unnamed field in the middle of a struct, call `cx.bug`.
                    if let None = name {
                        cx.span_bug(trait_span, "unnamed field in named struct")
                    }

                    let mut name_ = get_ident(name.unwrap());

                    // Optionally change the name of the field when the
                    // #[nbt_field = "fieldX"] attribute is present on the item.
                    for ref attr in attrs {
                        if attr.check_name("nbt_field") {
                            if let Some(s) = attr.value_str() {
                                name_ = s;
                            } else {
                                cx.span_err(span, "`#[nbt_field]` requires a &str value.");
                                return cx.expr_fail(trait_span, InternedString::new(""));
                            }
                            break;
                        }
                    }

                    // Apply the closure on this named field.
                    stmts.push(call_nbt_fmt(span, self_.clone(), name_));
                }
            }

            // Creates a `close_nbt(dst)` expression to add to the end of
            // the block.
            let close_nbt_path = pathexpr!(cx, trait_span, nbt::serialize::close_nbt);
            let close = cx.expr_call(trait_span, close_nbt_path, vec![dst_expr.clone()]);

            cx.expr_block(cx.block(trait_span, stmts, Some(close)))
        },
        _ => cx.span_bug(trait_span, "impossible substructure in `#[derive(NbtFmt)]`")
    }
}

fn cs_read_bare_nbt(cx: &mut ExtCtxt, trait_span: Span, substr: &Substructure) -> P<Expr> {
    match *substr.fields {
        StaticStruct(_, _) => cx.expr_unreachable(trait_span),
        _ => cx.span_bug(trait_span, "impossible substructure in `#[derive(NbtFmt)]`")
    }
}
<|endoftext|>


<commit_before>use ll::platform::*;
use ll::windef::*;

// extern "stdcall" fn(HWND, UINT, WPARAM, LPARAM) -> LRESULT
pub type WNDPROC = *c_void;

pub struct SECURITY_ATTRIBUTES {
    nLength: DWORD,
    lpSecurityDescriptor: LPVOID,
    bInheritHandle: BOOL,
}

pub struct PROCESS_INFORMATION {
    hProcess: HANDLE,
    hTread: HANDLE,
    dwProcessId: DWORD,
    dwThreadId: DWORD,
}

pub struct STARTUPINFO {
    cb: DWORD,
    lpReserved: LPWSTR,
    lpDesktop: LPWSTR,
    lpTitle: LPWSTR,
    dwX: DWORD,
    dwY: DWORD,
    dwXSize: DWORD,
    dwYSize: DWORD,
    dwXCountChars: DWORD,
    dwYCountChars: DWORD,
    dwFillAttribute: DWORD,
    dwFlags: DWORD,
    wShowWindow: WORD,
    cbReserved2: WORD,
    lpReserved2: LPBYTE,
    hStdInput: HANDLE,
    hStdOutput: HANDLE,
    hStdError: HANDLE,
}

pub struct WNDCLASSEX {
    cbSize: UINT,
    style: UINT,
    lpfnWndProc: WNDPROC,
    cbClsExtra: c_int,
    cbWndExtra: c_int,
    hInstance: HINSTANCE,
    hIcon: HICON,
    hCursor: HCURSOR,
    hbrBackground: HBRUSH,
    lpszMenuName: LPCWSTR,
    lpszClassName: LPCWSTR,
    hIconSm: HICON,
}

pub struct CREATESTRUCT {
    lpCreateParams: LPVOID,
    hInstance: HINSTANCE,
    hMenu: HMENU,
    hwndParent: HWND,
    cy: c_int,
    cx: c_int,
    y: c_int,
    x: c_int,
    style: LONG,
    lpszName: LPCWSTR,
    lpszClass: LPCWSTR,
    dwExStyle: DWORD,
}

pub struct POINT {
    x: LONG,
    y: LONG,
}

pub struct MSG {
    hwnd: HWND,
    message: UINT,
    wParam: WPARAM,
    lParam: LPARAM,
    time: DWORD,
    pt: POINT,
}

pub struct RECT {
    left: LONG,
    top: LONG,
    right: LONG,
    bottom: LONG,
}

pub struct PAINTSTRUCT {
    hdc: HDC,
    fErase: BOOL,
    rcPaint: RECT,
    fRestore: BOOL,
    fIncUpdate: BOOL,
    rgbReserved: *[BYTE, ..32],
}

// kernel32
extern "stdcall" {
    pub fn GetModuleHandleW(lpModuleName: LPCWSTR) -> HMODULE;

    pub fn GetLastError() -> DWORD;

    pub fn CreateProcessW(
        lpApplicationName: LPCWSTR, lpCommandLine: LPWSTR,
        lpProcessAttributes: *SECURITY_ATTRIBUTES,
        lpThreadAttributes: *SECURITY_ATTRIBUTES,
        bInheritHandles: BOOL,
        dwCreationFlags: DWORD,
        lpEnvironment: LPVOID,
        lpCurrentDirectory: LPCWSTR,
        lpStartupInfo: LPSTARTUPINFO,
        lpProcessInformation: LPPROCESS_INFORMATION
    ) -> BOOL;
}

// user32
extern "stdcall" {
    pub fn CreateWindowExW(extrastyle: DWORD, classname: LPCWSTR,
            windowname: LPCWSTR, style: DWORD,
            x: c_int, y: c_int, width: c_int, height: c_int,
            parent: HWND, menu: HMENU, instance: HINSTANCE, param: LPVOID
    ) -> HWND;

    pub fn ShowWindow(hwnd: HWND, nCmdShow: c_int) -> BOOL;

    pub fn UpdateWindow(hwnd: HWND) -> BOOL;

    pub fn BeginPaint(hwnd: HWND, lpPaint: *PAINTSTRUCT) -> HDC;

    pub fn EndPaint(hwnd: HWND, lpPaint: *PAINTSTRUCT) -> BOOL;

    pub fn MessageBoxW(
            hWnd: HWND, lpText: LPCWSTR, lpCaption: LPCWSTR, uType: UINT
    ) -> c_int;

    pub fn RegisterClassExW(lpwcx: *WNDCLASSEX) -> ATOM;

    pub fn DefWindowProcW(
            hwnd: HWND, msg: UINT, wparam: WPARAM, lparam: LPARAM
    ) -> LRESULT;

    pub fn GetMessageW(
            lpMsg: *MSG, hWnd: HWND,
            wMsgFilterMin: UINT, wMsgFilterMAx: UINT
    ) -> BOOL;

    pub fn PeekMessageW(
            lpMsg: *MSG, hWnd: HWND,
            wMsgFilterMin: UINT, wMsgFilterMAx: UINT, wRemoveMsg: UINT
    ) -> BOOL;

    pub fn PostMessageW(
            hWnd: HWND, Msg: UINT, wParam: WPARAM, lParam: LPARAM
    ) -> BOOL;

    pub fn PostQuitMessage(nExitCode: c_int);

    pub fn TranslateMessage(lpMsg: *MSG) -> BOOL;

    pub fn DispatchMessageW(lpMsg: *MSG) -> LRESULT;

    // 32-bit only
    pub fn GetClassLongW(hwnd: HWND, nIndex: c_int) -> DWORD;

    // 32-bit only
    pub fn SetClassLongW(
            hwnd: HWND, nIndex: c_int, dwNewLong: LONG
    ) -> DWORD;

    pub fn LoadImageW(
        hinst: HINSTANCE, name: LPCWSTR, type_: UINT,
        xDesired: c_int, yDesired: c_int, load: UINT
    ) -> HANDLE;
}

// gdi32
extern "stdcall" {
    pub fn TextOutW(
            hdc: HDC, nXStart: c_int, nYStart: c_int,
            lpString: LPWSTR, cchString: c_int
    ) -> BOOL;
}
<commit_msg>Set cfg(target_arch) for x86-only fns<commit_after>use ll::platform::*;
use ll::windef::*;

// extern "stdcall" fn(HWND, UINT, WPARAM, LPARAM) -> LRESULT
pub type WNDPROC = *c_void;

pub struct SECURITY_ATTRIBUTES {
    nLength: DWORD,
    lpSecurityDescriptor: LPVOID,
    bInheritHandle: BOOL,
}

pub struct PROCESS_INFORMATION {
    hProcess: HANDLE,
    hTread: HANDLE,
    dwProcessId: DWORD,
    dwThreadId: DWORD,
}

pub struct STARTUPINFO {
    cb: DWORD,
    lpReserved: LPWSTR,
    lpDesktop: LPWSTR,
    lpTitle: LPWSTR,
    dwX: DWORD,
    dwY: DWORD,
    dwXSize: DWORD,
    dwYSize: DWORD,
    dwXCountChars: DWORD,
    dwYCountChars: DWORD,
    dwFillAttribute: DWORD,
    dwFlags: DWORD,
    wShowWindow: WORD,
    cbReserved2: WORD,
    lpReserved2: LPBYTE,
    hStdInput: HANDLE,
    hStdOutput: HANDLE,
    hStdError: HANDLE,
}

pub struct WNDCLASSEX {
    cbSize: UINT,
    style: UINT,
    lpfnWndProc: WNDPROC,
    cbClsExtra: c_int,
    cbWndExtra: c_int,
    hInstance: HINSTANCE,
    hIcon: HICON,
    hCursor: HCURSOR,
    hbrBackground: HBRUSH,
    lpszMenuName: LPCWSTR,
    lpszClassName: LPCWSTR,
    hIconSm: HICON,
}

pub struct CREATESTRUCT {
    lpCreateParams: LPVOID,
    hInstance: HINSTANCE,
    hMenu: HMENU,
    hwndParent: HWND,
    cy: c_int,
    cx: c_int,
    y: c_int,
    x: c_int,
    style: LONG,
    lpszName: LPCWSTR,
    lpszClass: LPCWSTR,
    dwExStyle: DWORD,
}

pub struct POINT {
    x: LONG,
    y: LONG,
}

pub struct MSG {
    hwnd: HWND,
    message: UINT,
    wParam: WPARAM,
    lParam: LPARAM,
    time: DWORD,
    pt: POINT,
}

pub struct RECT {
    left: LONG,
    top: LONG,
    right: LONG,
    bottom: LONG,
}

pub struct PAINTSTRUCT {
    hdc: HDC,
    fErase: BOOL,
    rcPaint: RECT,
    fRestore: BOOL,
    fIncUpdate: BOOL,
    rgbReserved: *[BYTE, ..32],
}

// kernel32
extern "stdcall" {
    pub fn GetModuleHandleW(lpModuleName: LPCWSTR) -> HMODULE;

    pub fn GetLastError() -> DWORD;

    pub fn CreateProcessW(
        lpApplicationName: LPCWSTR, lpCommandLine: LPWSTR,
        lpProcessAttributes: *SECURITY_ATTRIBUTES,
        lpThreadAttributes: *SECURITY_ATTRIBUTES,
        bInheritHandles: BOOL,
        dwCreationFlags: DWORD,
        lpEnvironment: LPVOID,
        lpCurrentDirectory: LPCWSTR,
        lpStartupInfo: LPSTARTUPINFO,
        lpProcessInformation: LPPROCESS_INFORMATION
    ) -> BOOL;
}

// user32
extern "stdcall" {
    pub fn CreateWindowExW(extrastyle: DWORD, classname: LPCWSTR,
            windowname: LPCWSTR, style: DWORD,
            x: c_int, y: c_int, width: c_int, height: c_int,
            parent: HWND, menu: HMENU, instance: HINSTANCE, param: LPVOID
    ) -> HWND;

    pub fn ShowWindow(hwnd: HWND, nCmdShow: c_int) -> BOOL;

    pub fn UpdateWindow(hwnd: HWND) -> BOOL;

    pub fn BeginPaint(hwnd: HWND, lpPaint: *PAINTSTRUCT) -> HDC;

    pub fn EndPaint(hwnd: HWND, lpPaint: *PAINTSTRUCT) -> BOOL;

    pub fn MessageBoxW(
            hWnd: HWND, lpText: LPCWSTR, lpCaption: LPCWSTR, uType: UINT
    ) -> c_int;

    pub fn RegisterClassExW(lpwcx: *WNDCLASSEX) -> ATOM;

    pub fn DefWindowProcW(
            hwnd: HWND, msg: UINT, wparam: WPARAM, lparam: LPARAM
    ) -> LRESULT;

    pub fn GetMessageW(
            lpMsg: *MSG, hWnd: HWND,
            wMsgFilterMin: UINT, wMsgFilterMAx: UINT
    ) -> BOOL;

    pub fn PeekMessageW(
            lpMsg: *MSG, hWnd: HWND,
            wMsgFilterMin: UINT, wMsgFilterMAx: UINT, wRemoveMsg: UINT
    ) -> BOOL;

    pub fn PostMessageW(
            hWnd: HWND, Msg: UINT, wParam: WPARAM, lParam: LPARAM
    ) -> BOOL;

    pub fn PostQuitMessage(nExitCode: c_int);

    pub fn TranslateMessage(lpMsg: *MSG) -> BOOL;

    pub fn DispatchMessageW(lpMsg: *MSG) -> LRESULT;

    #[cfg(target_arch = "x86")]
    pub fn GetClassLongW(hwnd: HWND, nIndex: c_int) -> DWORD;

    #[cfg(target_arch = "x86")]
    pub fn SetClassLongW(
            hwnd: HWND, nIndex: c_int, dwNewLong: LONG
    ) -> DWORD;

    pub fn LoadImageW(
        hinst: HINSTANCE, name: LPCWSTR, type_: UINT,
        xDesired: c_int, yDesired: c_int, load: UINT
    ) -> HANDLE;
}

// gdi32
extern "stdcall" {
    pub fn TextOutW(
            hdc: HDC, nXStart: c_int, nYStart: c_int,
            lpString: LPWSTR, cchString: c_int
    ) -> BOOL;
}
<|endoftext|>


<commit_before>#[macro_use] extern crate clap;
extern crate adapton_lab;

use std::rc::Rc;
use std::io::BufReader;
use std::io::BufWriter;
use std::io::Write;
use std::io::BufRead;
use std::fs::File;
use std::collections::HashMap;

use adapton_lab::labviz::{Div,WriteHTML};

// Temp: Make this better at some point?
type Graph = HashMap<Rc<String>, Vec<Rc<String>>>;
type NodeSet = HashMap<Rc<String>,()>;
type NodeCount = HashMap<Rc<String>,usize>;

struct Options {
    tooltips: bool,
    tooltips_visited: bool,
}

impl Options {
    fn new() -> Self {
        Options {
            tooltips:true,
            tooltips_visited:false,
        }
    }
}

struct St {
    nodes: NodeSet,
    leaves:NodeSet,
    roots: NodeSet,
    graph: Graph,
    edges: Vec<(Rc<String>, Rc<String>)>,
    rev_graph:Graph,
}

impl St {
    fn new() -> Self {
        St {
            nodes: HashMap::new(),
            leaves:HashMap::new(),
            roots: HashMap::new(),
            graph: HashMap::new(),
            edges: Vec::new(),
            rev_graph:HashMap::new()
        }
    }
    fn process_nodes(self:&mut Self) {
        self.leaves=HashMap::new();
        self.roots=HashMap::new();
        for (node,_) in self.nodes.iter() {
            match self.graph.get(node) {
                None => { self.leaves.insert(node.clone(),()); },
                Some(_out) => {}
            };
            match self.rev_graph.get(node) {
                None => { self.roots.insert(node.clone(),()); },
                Some(_out) => {}
            };
        }
    }
    fn add_edge(self:&mut Self, src:Rc<String>, tgt:Rc<String>) {
        self.nodes.insert(src.clone(), ());
        self.nodes.insert(tgt.clone(), ());
        let edge = if false {
            //(Rc::new(v[0].to_string()), Rc::new(v[1].to_string()))
            (src, tgt)
        } else {
            //(Rc::new(v[1].to_string()), Rc::new(v[0].to_string()))
            (tgt, src)
        };
        self.edges.push(edge.clone());

        let inserted : bool = match self.graph.get_mut(&edge.0) {
            None => { false }
            Some(out) => {
                out.push(edge.1.clone());
                true
            },
        };
        if !inserted {
            self.graph.insert(edge.0.clone(), vec![ edge.1.clone() ]);
        };

        let inserted : bool = match self.rev_graph.get_mut(&edge.1) {
            None => { false }
            Some(out) => {
                out.push(edge.0.clone());
                true
            },
        };
        if !inserted {
            self.rev_graph.insert(edge.1, vec![ edge.0 ]);
        };
    }
}

fn main() {
    let mut options = Options::new();
    let args = clap::App::new("dep-viz")
        .version("0.1")
        .author("Matthew Hammer <matthew.hammer@colorado.edu>")
        .about("Consumes Rustc dependency information; Produces visualizations")
        .args_from_usage("\
                --tooltips-visited    'show tooltips for visited nodes'
            -i, --infile=[infile]     'name for input file'
            -o, --outfile=[outfile]   'name for output file'")
    .get_matches();
    let infile_name = args.value_of("infile").unwrap_or("dep_graph.txt");
    let outfile_name = args.value_of("outfile").unwrap_or("dep_graph.html");
    options.tooltips_visited = value_t!(args, "tooltips-visited", bool).unwrap_or(false);
    let f = File::open(infile_name).unwrap();
    let file = BufReader::new(&f);
    let mut st = St::new();

    println!("Reading input file: {}", infile_name);
    for (_num, line) in file.lines().enumerate() {
        let line = line.unwrap();
        let v: Vec<&str> = line.split(" -> ").map(|s|s.trim()).collect();
        assert_eq!(v.len(), 2);
        st.add_edge(Rc::new(v[0].to_string()),
                    Rc::new(v[1].to_string()));
    }
    println!("...Read input file: {}", infile_name);
    st.process_nodes();
    println!("  Found {} edges", st.edges.len());
    println!("  Found {} nodes", st.nodes.len());
    println!("    Found {} root nodes", st.roots.len());
    println!("    Found {} leaf nodes", st.leaves.len());

    println!("\nPerforming DFS on graph...");
    let mut stack = vec![];
    for (node,_) in st.roots.iter() {
        stack.push(node.clone());
        //break;
    }

    let (div, visited) = dfs(&options, &st.graph, stack);
    println!("...Performed DFS on graph.");
    println!("  Visited {} nodes, {:.1}% of total", visited.len(),
             100f32 * (visited.len() as f32) / (st.nodes.len() as f32));

    println!("\nFinding unvisited graph nodes...");
    let mut unvisited : NodeSet = HashMap::new();
    for (node, _) in st.nodes.iter() {
        if visited.get(node) == None {
            unvisited.insert(node.clone(), ());
            //println!("unvisited: {}", node);
        }
    }
    assert_eq!(visited.len() + unvisited.len(),
               st.nodes.len());
    //println!("...Found graph nodes.");
    println!("...Found {} unvisited graph nodes, {:.1}% of total.",
             unvisited.len(),
             100f32 * (unvisited.len() as f32) / (st.nodes.len() as f32));

    println!("Writing HTML output: {}", outfile_name);
    let outfile = File::create(outfile_name).unwrap();
    let mut buf_writer = BufWriter::new(outfile);
    let _ = buf_writer.write_all(style_string().as_bytes());
    div.write_html(&mut buf_writer);
    let _ = buf_writer.flush();
    println!("..Wrote HTML output: {}", outfile_name);
}

fn dfs (options:&Options, graph: &Graph, stack:Vec<Rc<String>>) -> (Div, NodeCount) {
    let mut visited:NodeCount = HashMap::new();
    let mut divs:Vec<Div> = Vec::new();
    for n in stack.iter() {
        divs.push(dfs_rec(options, graph, &mut visited, 0, n));
        //if visited.len() > 10000 { break } else { continue }
    }
    (Div{tag:"dfs".to_string(),
         classes:vec![],
         extent:Box::new(divs),
         text: None}, visited)
}

fn cons_of_node_name(node:&Rc<String>) -> String {
    let cons : Vec<&str> = node.trim().split("(").collect();
    assert!(cons.len() > 0 && cons[0] != "");
    cons[0].to_string()
}

fn append_classes_of_node(node:&Rc<String>, mut classes:Vec<String>) -> Vec<String> {
    classes.push(cons_of_node_name(node));
    classes
}

fn append_tooltip(options:&Options, node:&Rc<String>, mut extent:Vec<Div>, visited:bool, depth: usize) -> Vec<Div> {
    if options.tooltips && (!visited || options.tooltips_visited) {
        let show_full_details_depth = 2;
        extent.insert(0, Div{tag:"tooltip".to_string(),
                             classes:vec![],
                             extent:Box::new(vec![]),
                             text: Some(
                                 format!("{}: {}", depth,
                                         if !visited && depth < show_full_details_depth
                                         { (**node).clone() }
                                         else
                                         { cons_of_node_name(node) }))
        });
        extent
    }
    else {
        extent
    }
}

fn dfs_rec (options:&Options, graph: &Graph, visited: &mut NodeCount, depth:usize, node:&Rc<String>) -> Div {
    if visited.get(node) == None {
        visited.insert(node.clone(),1);
        match graph.get(node) {
            None => {
                /* Has no children */
                Div{tag:if false {(**node).clone()} else { "".to_string() },
                    classes:append_classes_of_node(node, vec![
                        "node".to_string(),
                        "no-extent".to_string()
                    ]),
                    extent:Box::new(append_tooltip(options, node, vec![], false, depth)),
                    text:None}
            }
            Some(out) => {
                /* Has children */
                let mut divs = vec![];
                for n in out {
                    divs.push(dfs_rec(options, graph, visited, depth+1, n))
                }
                Div{tag:if false {(**node).clone()} else { "".to_string() },
                    classes:append_classes_of_node(node, vec![
                        "node".to_string()
                    ]),
                    extent:Box::new(append_tooltip(options, node, divs, false, depth)),
                    text:None}
            }
        }
    }
    else {
        // increment counter
        let node_count = visited.get(node).unwrap() + 1;
        visited.insert(node.clone(), node_count);
        // Already visited
        Div{tag:if false {(**node).clone()} else { "".to_string() },
            classes:vec![
                "node".to_string(),
                "visited".to_string()
            ],
            extent:Box::new(append_tooltip(options, node, vec![], true, depth)),
            //extent:Box::new(vec![]),
            text:None}
    }
}

pub fn style_string() -> &'static str {
"
<html>
<head>
<script src=\"https://ajax.googleapis.com/ajax/libs/jquery/3.1.1/jquery.min.js\"></script>

<style>
div {
  display: inline
}
body {
  display: inline;
  color: #aa88cc;
  background: #313;
  font-family: sans-serif;
  text-decoration: none;
  padding: 0px;
  margin: 0px;
}
body:visited {
  color: #aa88cc;
}
a {
  text-decoration: none;
}
a:hover {
  text-decoration: underline;
}
hr {
  display: block;
  float: left;
  clear: both;
  width: 0px;
  border: none;
}

.node {
  color: black;
  display: inline-block;
  border-style: solid;
  border-color: #221133;
  border-width: 1px;
  background: #ffccff;
  font-size: 0px;
  padding: 0px;
  margin: 1px;
  border-radius: 5px;
}

.visited {
  border-width: 2px;
}

.no-extent {
  padding: 3px;
}
.tooltip {
  visibility: hidden;
  background-color: #324;
  border-style: solid;
  border-color: #eeeeee;
  border-width: 1px;
  color: #eae;
  text-align: left;
  padding: 5px 0;
  border-radius: 2px;
  font-size: 12px;
  position: absolute;
  z-index: 1;
}
.node:hover {
  border-color: green;
}
.node:hover > .tooltip {
  visibility: visible;
}

.WorkProduct {
  border-width: 2px;
  border-color: blue;
  background: #999;
}

.MetaData {
  border-color: #000055;
  background: #0000ff;
}

.Hir {
  border-color: #005555;
  background: #00aaff;
}

</style>
</head>
<body>
"
}
<commit_msg>clap for tips<commit_after>extern crate clap;
extern crate adapton_lab;

use std::rc::Rc;
use std::io::BufReader;
use std::io::BufWriter;
use std::io::Write;
use std::io::BufRead;
use std::fs::File;
use std::collections::HashMap;

use adapton_lab::labviz::{Div,WriteHTML};

// Temp: Make this better at some point?
type Graph = HashMap<Rc<String>, Vec<Rc<String>>>;
type NodeSet = HashMap<Rc<String>,()>;
type NodeCount = HashMap<Rc<String>,usize>;

#[derive(Debug)]
struct Options {
    tooltips: bool,
    tooltips_visited: bool,
}

impl Options {
    fn new() -> Self {
        Options {
            tooltips:true,
            tooltips_visited:false,
        }
    }
}

struct St {
    nodes: NodeSet,
    leaves:NodeSet,
    roots: NodeSet,
    graph: Graph,
    edges: Vec<(Rc<String>, Rc<String>)>,
    rev_graph:Graph,
}

impl St {
    fn new() -> Self {
        St {
            nodes: HashMap::new(),
            leaves:HashMap::new(),
            roots: HashMap::new(),
            graph: HashMap::new(),
            edges: Vec::new(),
            rev_graph:HashMap::new()
        }
    }
    fn process_nodes(self:&mut Self) {
        self.leaves=HashMap::new();
        self.roots=HashMap::new();
        for (node,_) in self.nodes.iter() {
            match self.graph.get(node) {
                None => { self.leaves.insert(node.clone(),()); },
                Some(_out) => {}
            };
            match self.rev_graph.get(node) {
                None => { self.roots.insert(node.clone(),()); },
                Some(_out) => {}
            };
        }
    }
    fn add_edge(self:&mut Self, src:Rc<String>, tgt:Rc<String>) {
        self.nodes.insert(src.clone(), ());
        self.nodes.insert(tgt.clone(), ());
        let edge = if false {
            //(Rc::new(v[0].to_string()), Rc::new(v[1].to_string()))
            (src, tgt)
        } else {
            //(Rc::new(v[1].to_string()), Rc::new(v[0].to_string()))
            (tgt, src)
        };
        self.edges.push(edge.clone());

        let inserted : bool = match self.graph.get_mut(&edge.0) {
            None => { false }
            Some(out) => {
                out.push(edge.1.clone());
                true
            },
        };
        if !inserted {
            self.graph.insert(edge.0.clone(), vec![ edge.1.clone() ]);
        };

        let inserted : bool = match self.rev_graph.get_mut(&edge.1) {
            None => { false }
            Some(out) => {
                out.push(edge.0.clone());
                true
            },
        };
        if !inserted {
            self.rev_graph.insert(edge.1, vec![ edge.0 ]);
        };
    }
}

fn main() {
    let mut options = Options::new();
    let args = clap::App::new("dep-viz")
        .version("0.1")
        .author("Matthew Hammer <matthew.hammer@colorado.edu>")
        .about("Consumes Rustc dependency information; Produces visualizations")
        .args_from_usage("\
                --no-tips            'do not show tips for nodes on hover'
                --tips-visited       'show tips even for visited nodes'
            -i, --infile=[infile]    'name for input file'
            -o, --outfile=[outfile]  'name for output file'")
    .get_matches();
    let infile_name = args.value_of("infile").unwrap_or("dep_graph.txt");
    let outfile_name = args.value_of("outfile").unwrap_or("dep_graph.html");

    options.tooltips = !(args.is_present("no-tips"));
    options.tooltips_visited = args.is_present("tips-visited");

    println!("{:?}", options);

    println!("Reading input file: {}", infile_name);
    let f = File::open(infile_name).unwrap();
    let file = BufReader::new(&f);
    let mut st = St::new();
    for (_num, line) in file.lines().enumerate() {
        let line = line.unwrap();
        let v: Vec<&str> = line.split(" -> ").map(|s|s.trim()).collect();
        assert_eq!(v.len(), 2);
        st.add_edge(Rc::new(v[0].to_string()),
                    Rc::new(v[1].to_string()));
    }
    println!("...Read input file: {}", infile_name);
    st.process_nodes();
    println!("  Found {} edges", st.edges.len());
    println!("  Found {} nodes", st.nodes.len());
    println!("    Found {} root nodes", st.roots.len());
    println!("    Found {} leaf nodes", st.leaves.len());

    println!("\nPerforming DFS on graph...");
    let mut stack = vec![];
    for (node,_) in st.roots.iter() {
        stack.push(node.clone());
        //break;
    }

    let (div, visited) = dfs(&options, &st.graph, stack);
    println!("...Performed DFS on graph.");
    println!("  Visited {} nodes, {:.1}% of total", visited.len(),
             100f32 * (visited.len() as f32) / (st.nodes.len() as f32));

    println!("\nFinding unvisited graph nodes...");
    let mut unvisited : NodeSet = HashMap::new();
    for (node, _) in st.nodes.iter() {
        if visited.get(node) == None {
            unvisited.insert(node.clone(), ());
            //println!("unvisited: {}", node);
        }
    }
    assert_eq!(visited.len() + unvisited.len(),
               st.nodes.len());
    //println!("...Found graph nodes.");
    println!("...Found {} unvisited graph nodes, {:.1}% of total.",
             unvisited.len(),
             100f32 * (unvisited.len() as f32) / (st.nodes.len() as f32));

    println!("Writing HTML output: {}", outfile_name);
    let outfile = File::create(outfile_name).unwrap();
    let mut buf_writer = BufWriter::new(outfile);
    let _ = buf_writer.write_all(style_string().as_bytes());
    div.write_html(&mut buf_writer);
    let _ = buf_writer.flush();
    println!("..Wrote HTML output: {}", outfile_name);
}

fn dfs (options:&Options, graph: &Graph, stack:Vec<Rc<String>>) -> (Div, NodeCount) {
    let mut visited:NodeCount = HashMap::new();
    let mut divs:Vec<Div> = Vec::new();
    for n in stack.iter() {
        divs.push(dfs_rec(options, graph, &mut visited, 0, n));
        //if visited.len() > 10000 { break } else { continue }
    }
    (Div{tag:"dfs".to_string(),
         classes:vec![],
         extent:Box::new(divs),
         text: None}, visited)
}

fn cons_of_node_name(node:&Rc<String>) -> String {
    let cons : Vec<&str> = node.trim().split("(").collect();
    assert!(cons.len() > 0 && cons[0] != "");
    cons[0].to_string()
}

fn append_classes_of_node(node:&Rc<String>, mut classes:Vec<String>) -> Vec<String> {
    classes.push(cons_of_node_name(node));
    classes
}

fn append_tooltip(options:&Options, node:&Rc<String>, mut extent:Vec<Div>, visited:bool, depth: usize) -> Vec<Div> {
    if options.tooltips && (!visited || options.tooltips_visited) {
        let show_full_details_depth = 2;
        extent.insert(0, Div{tag:"tooltip".to_string(),
                             classes:vec![],
                             extent:Box::new(vec![]),
                             text: Some(
                                 format!("{}: {}", depth,
                                         if !visited && depth < show_full_details_depth
                                         { (**node).clone() }
                                         else
                                         { cons_of_node_name(node) }))
        });
        extent
    }
    else {
        extent
    }
}

fn dfs_rec (options:&Options, graph: &Graph, visited: &mut NodeCount, depth:usize, node:&Rc<String>) -> Div {
    if visited.get(node) == None {
        visited.insert(node.clone(),1);
        match graph.get(node) {
            None => {
                /* Has no children */
                Div{tag:if false {(**node).clone()} else { "".to_string() },
                    classes:append_classes_of_node(node, vec![
                        "node".to_string(),
                        "no-extent".to_string()
                    ]),
                    extent:Box::new(append_tooltip(options, node, vec![], false, depth)),
                    text:None}
            }
            Some(out) => {
                /* Has children */
                let mut divs = vec![];
                for n in out {
                    divs.push(dfs_rec(options, graph, visited, depth+1, n))
                }
                Div{tag:if false {(**node).clone()} else { "".to_string() },
                    classes:append_classes_of_node(node, vec![
                        "node".to_string()
                    ]),
                    extent:Box::new(append_tooltip(options, node, divs, false, depth)),
                    text:None}
            }
        }
    }
    else {
        // increment counter
        let node_count = visited.get(node).unwrap() + 1;
        visited.insert(node.clone(), node_count);
        // Already visited
        Div{tag:if false {(**node).clone()} else { "".to_string() },
            classes:vec![
                "node".to_string(),
                "visited".to_string()
            ],
            extent:Box::new(append_tooltip(options, node, vec![], true, depth)),
            //extent:Box::new(vec![]),
            text:None}
    }
}

pub fn style_string() -> &'static str {
"
<html>
<head>
<script src=\"https://ajax.googleapis.com/ajax/libs/jquery/3.1.1/jquery.min.js\"></script>

<style>
div {
  display: inline
}
body {
  display: inline;
  color: #aa88cc;
  background: #313;
  font-family: sans-serif;
  text-decoration: none;
  padding: 0px;
  margin: 0px;
}
body:visited {
  color: #aa88cc;
}
a {
  text-decoration: none;
}
a:hover {
  text-decoration: underline;
}
hr {
  display: block;
  float: left;
  clear: both;
  width: 0px;
  border: none;
}

.node {
  color: black;
  display: inline-block;
  border-style: solid;
  border-color: #221133;
  border-width: 1px;
  background: #ffccff;
  font-size: 0px;
  padding: 0px;
  margin: 1px;
  border-radius: 5px;
}

.visited {
  border-width: 2px;
}

.no-extent {
  padding: 3px;
}
.tooltip {
  visibility: hidden;
  background-color: #324;
  border-style: solid;
  border-color: #eeeeee;
  border-width: 1px;
  color: #eae;
  text-align: left;
  padding: 5px 0;
  border-radius: 2px;
  font-size: 12px;
  position: absolute;
  z-index: 1;
}
.node:hover {
  border-color: green;
}
.node:hover > .tooltip {
  visibility: visible;
}

.WorkProduct {
  border-width: 2px;
  border-color: blue;
  background: #999;
}

.MetaData {
  border-color: #000055;
  background: #0000ff;
}

.Hir {
  border-color: #005555;
  background: #00aaff;
}

</style>
</head>
<body>
"
}
<|endoftext|>