<commit_before>#![crate_type = "bin"]
#![feature(collections)]

extern crate gtk;
extern crate glib;
extern crate sysinfo;

use gtk::{WindowTrait, ContainerTrait, WidgetTrait, ButtonSignals, BoxTrait};
use gtk::{IconSize, Orientation, ReliefStyle};
use sysinfo::*;
use gtk::signal::Inhibit;
use gtk::signal::{WidgetSignals, TreeViewSignals};
use std::collections::VecMap;
use std::str::FromStr;
use std::rc::Rc;
use std::cell::{RefCell, RefMut};
use std::ops::DerefMut;

struct NoteBook {
    notebook: gtk::NoteBook,
    tabs: Vec<gtk::Box>
}

impl NoteBook {
    fn new() -> NoteBook {
        NoteBook {
            notebook: gtk::NoteBook::new().unwrap(),
            tabs: Vec::new()
        }
    }

    fn create_tab<'a, Widget: gtk::WidgetTrait>(&mut self, title: &'a str, widget: &Widget) -> Option<u32> {
        let label = gtk::Label::new(title).unwrap();
        let tab = gtk::Box::new(Orientation::Horizontal, 0).unwrap();

        tab.pack_start(&label, false, false, 0);
        tab.show_all();

        let index = match self.notebook.append_page(widget, Some(&tab)) {
            Some(index) => index,
            _ => return None
        };

        self.tabs.push(tab);

        Some(index)
    }
}

struct Procs {
    left_tree: gtk::TreeView,
    scroll: gtk::ScrolledWindow,
    current_pid: Rc<RefCell<Option<String>>>,
    kill_button: Rc<RefCell<gtk::Button>>,
    vertical_layout: gtk::Box,
    list_store: gtk::ListStore
}

impl Procs {
    pub fn new<'a>(proc_list: &VecMap<Processus>) -> Procs {
        let mut left_tree = gtk::TreeView::new().unwrap();
        let mut scroll = gtk::ScrolledWindow::new(None, None).unwrap();
        let mut current_pid = Rc::new(RefCell::new(None));
        let mut kill_button = Rc::new(RefCell::new(gtk::Button::new_with_label("End task").unwrap()));
        let mut current_pid1 = current_pid.clone();
        let mut current_pid2 = current_pid.clone();
        let mut kill_button1 = kill_button.clone();

        scroll.set_min_content_height(800);
        scroll.set_min_content_width(600);

        let mut columns : Vec<gtk::TreeViewColumn> = Vec::new();

        append_column("pid", &mut columns);
        append_column("process name", &mut columns);
        append_column("cpu usage", &mut columns);
        append_column("memory usage", &mut columns);

        for i in columns {
            left_tree.append_column(&i);
        }

        let mut list_store = gtk::ListStore::new(&[glib::Type::String, glib::Type::String, glib::Type::String, glib::Type::String]).unwrap();
        for (_, pro) in proc_list {
            create_and_fill_model(&mut list_store, pro.pid, &pro.name, pro.cpu_usage, pro.memory);
        }

        left_tree.set_model(&list_store.get_model().unwrap());
        left_tree.set_headers_visible(true);
        scroll.add(&left_tree);
        let mut vertical_layout = gtk::Box::new(gtk::Orientation::Vertical, 0).unwrap();

        left_tree.connect_cursor_changed(move |tree_view| {
            match tree_view.get_selection() {
                Some(selection) => {
                    let model = tree_view.get_model().unwrap();
                    let mut iter = gtk::TreeIter::new();

                    if selection.get_selected(&model, &mut iter) {
                        let pid = model.get_value(&iter, 0).get_string();
                        let mut tmp = current_pid1.borrow_mut();
                        *tmp = pid;
                    }
                    (*kill_button1.borrow_mut()).set_sensitive((*current_pid.borrow()).is_some());
                }
                None => {
                    let mut tmp = current_pid1.borrow_mut();
                    *tmp = None;
                }
            }
        });
        (*kill_button.borrow_mut()).set_sensitive(false);

        vertical_layout.add(&scroll);
        vertical_layout.add(&(*kill_button.borrow_mut()));
        Procs {
            left_tree: left_tree,
            scroll: scroll,
            current_pid: current_pid2.clone(),
            kill_button: kill_button,
            vertical_layout: vertical_layout,
            list_store: list_store
        }
    }
}

fn append_column(title: &str, v: &mut Vec<gtk::TreeViewColumn>) {
    let l = v.len();
    let renderer = gtk::CellRendererText::new().unwrap();

    v.push(gtk::TreeViewColumn::new().unwrap());
    let tmp = v.get_mut(l).unwrap();

    tmp.set_title(title);
    tmp.pack_start(&renderer, true);
    tmp.add_attribute(&renderer, "text", l as i32);
}

fn create_and_fill_model(list_store: &mut gtk::ListStore, pid: i64, name: &str, cpu: f32, memory: u64) {
    if name.len() < 1 {
        return;
    }
    let mut top_level = gtk::TreeIter::new();

    list_store.append(&mut top_level);
    list_store.set_string(&top_level, 0, &format!("{}", pid));
    list_store.set_string(&top_level, 1, name);
    list_store.set_string(&top_level, 2, &format!("{}", cpu));
    list_store.set_string(&top_level, 3, &format!("{}", memory));
}

fn update_window(w: &mut (&mut gtk::ListStore, Rc<RefCell<sysinfo::System>>, Rc<RefCell<Vec<gtk::ProgressBar>>>)) -> i32 {
    let mut model = w.0.get_model().unwrap();
    let mut iter = gtk::TreeIter::new();

    (*w.1.borrow_mut()).refresh();
    let mut entries : VecMap<Processus> = ((*w.1.borrow()).get_processus_list()).clone();
    let mut nb = model.iter_n_children(None);
    let mut i = 0;

    let v = &*w.2.borrow_mut();
    for pro in (*w.1.borrow()).get_process_list() {
        v[i].set_text(&format!("{:.2} %", pro.get_cpu_usage() * 100.));
        v[i].set_show_text(true);
        v[i].set_fraction(pro.get_cpu_usage() as f64);
        i += 1;
    }

    let mut i = 0;
    while i < nb {
        if model.iter_nth_child(&mut iter, None, i) {
            let pid : i64 = i64::from_str(&model.get_value(&iter, 0).get_string().unwrap()).unwrap();
            let mut to_delete = false;

            match entries.get(&(pid as usize)) {
                Some(p) => {
                    //w.0.set_string(&iter, 1, &p.name);
                    w.0.set_string(&iter, 2, &format!("{}", p.cpu_usage));
                    w.0.set_string(&iter, 3, &format!("{}", p.memory));
                    to_delete = true;
                }
                None => {
                    w.0.remove(&iter);
                }
            }
            if to_delete {
                entries.remove(&(pid as usize));
                nb = model.iter_n_children(None);
                i += 1;
            }
        } else {
            i += 1;
        }
    }
    for (_, pro) in entries {
        create_and_fill_model(&mut w.0, pro.pid, &pro.name, pro.cpu_usage, pro.memory);
    }
    1
}

fn main() {
    gtk::init();

    let mut window = gtk::Window::new(gtk::WindowType::TopLevel).unwrap();
    let mut sys : Rc<RefCell<sysinfo::System>> = Rc::new(RefCell::new(sysinfo::System::new()));
    let mut sys1 = sys.clone();
    let mut note = NoteBook::new();
    (*sys.borrow_mut()).refresh();
    let mut procs = Procs::new((*sys.borrow()).get_processus_list());
    let mut current_pid2 = procs.current_pid.clone();
    let mut sys1 = sys.clone();
    let mut sys2 = sys.clone();

    window.set_title("Processus viewer");
    window.set_window_position(gtk::WindowPosition::Center);

    window.connect_delete_event(|_, _| {
        gtk::main_quit();
        Inhibit(true)
    });

    (*procs.kill_button.borrow_mut()).connect_clicked(move |_| {
        let tmp = (*current_pid2.borrow_mut()).is_some() ;

        if tmp {
            let s = (*current_pid2.borrow()).clone();
            match (*sys.borrow_mut()).get_processus(i64::from_str(&s.unwrap()).unwrap()) {
                Some(p) => {
                    p.kill(Signal::Kill);
                },
                None => {}
            };
        }
    });

    let mut vertical_layout = gtk::Box::new(gtk::Orientation::Vertical, 0).unwrap();
    //let mut i = 0;

    vertical_layout.set_spacing(5);
    let mut v = Vec::new();
    let mut i = 1;
    for pro in (*sys1.borrow()).get_process_list() {
        v.push(gtk::ProgressBar::new().unwrap());
        let p : &gtk::ProgressBar = &v[v.len() - 1];
        let l = gtk::Label::new(&format!("{}", i)).unwrap();
        let horizontal_layout = gtk::Box::new(gtk::Orientation::Horizontal, 0).unwrap();

        p.set_text(&format!("{:.2} %", pro.get_cpu_usage() * 100.));
        p.set_show_text(true);
        p.set_fraction(pro.get_cpu_usage() as f64);
        horizontal_layout.pack_start(&l, false, false, 5);
        horizontal_layout.pack_start(p, true, true, 5);
        vertical_layout.add(&horizontal_layout);
        i += 1;
    }
    vertical_layout.pack_start(&gtk::Label::new("Memory").unwrap(), false, false, 15);
    vertical_layout.add(&gtk::Label::new(&format!("Total memory: {} kB", (*sys2.borrow()).get_total_memory())).unwrap());
    vertical_layout.add(&gtk::Label::new(&format!("Free memory: {} kB", (*sys2.borrow()).get_free_memory())).unwrap());
    vertical_layout.add(&gtk::Label::new(&format!("Total swap: {} kB", (*sys2.borrow()).get_total_swap())).unwrap());
    vertical_layout.add(&gtk::Label::new(&format!("Free swap: {} kB", (*sys2.borrow()).get_free_swap())).unwrap());
    let mut v_procs = Rc::new(RefCell::new(v));

    glib::timeout::add(1500, update_window, &mut (&mut procs.list_store, sys1.clone(), v_procs.clone()));
    //window.add(&vertical_layout);
    note.create_tab("Processus list", &procs.vertical_layout);
    //let t = gtk::Button::new_with_label("test").unwrap();
    note.create_tab("System usage", &vertical_layout);
    window.add(&note.notebook);
    window.show_all();
    gtk::main();
}
<commit_msg>Few display updates<commit_after>#![crate_type = "bin"]
#![feature(collections)]

extern crate gtk;
extern crate glib;
extern crate sysinfo;

use gtk::{WindowTrait, ContainerTrait, WidgetTrait, ButtonSignals, BoxTrait};
use gtk::{IconSize, Orientation, ReliefStyle};
use sysinfo::*;
use gtk::signal::Inhibit;
use gtk::signal::{WidgetSignals, TreeViewSignals};
use std::collections::VecMap;
use std::str::FromStr;
use std::rc::Rc;
use std::cell::{RefCell, RefMut};
use std::ops::DerefMut;

struct NoteBook {
    notebook: gtk::NoteBook,
    tabs: Vec<gtk::Box>
}

impl NoteBook {
    fn new() -> NoteBook {
        NoteBook {
            notebook: gtk::NoteBook::new().unwrap(),
            tabs: Vec::new()
        }
    }

    fn create_tab<'a, Widget: gtk::WidgetTrait>(&mut self, title: &'a str, widget: &Widget) -> Option<u32> {
        let label = gtk::Label::new(title).unwrap();
        let tab = gtk::Box::new(Orientation::Horizontal, 0).unwrap();

        tab.pack_start(&label, false, false, 0);
        tab.show_all();

        let index = match self.notebook.append_page(widget, Some(&tab)) {
            Some(index) => index,
            _ => return None
        };

        self.tabs.push(tab);

        Some(index)
    }
}

struct Procs {
    left_tree: gtk::TreeView,
    scroll: gtk::ScrolledWindow,
    current_pid: Rc<RefCell<Option<String>>>,
    kill_button: Rc<RefCell<gtk::Button>>,
    vertical_layout: gtk::Box,
    list_store: gtk::ListStore
}

impl Procs {
    pub fn new<'a>(proc_list: &VecMap<Processus>) -> Procs {
        let mut left_tree = gtk::TreeView::new().unwrap();
        let mut scroll = gtk::ScrolledWindow::new(None, None).unwrap();
        let mut current_pid = Rc::new(RefCell::new(None));
        let mut kill_button = Rc::new(RefCell::new(gtk::Button::new_with_label("End task").unwrap()));
        let mut current_pid1 = current_pid.clone();
        let mut current_pid2 = current_pid.clone();
        let mut kill_button1 = kill_button.clone();

        scroll.set_min_content_height(800);
        scroll.set_min_content_width(600);

        let mut columns : Vec<gtk::TreeViewColumn> = Vec::new();

        append_column("pid", &mut columns);
        append_column("process name", &mut columns);
        append_column("cpu usage", &mut columns);
        append_column("memory usage", &mut columns);

        for i in columns {
            left_tree.append_column(&i);
        }

        let mut list_store = gtk::ListStore::new(&[glib::Type::String, glib::Type::String, glib::Type::String, glib::Type::String]).unwrap();
        for (_, pro) in proc_list {
            create_and_fill_model(&mut list_store, pro.pid, &pro.name, pro.cpu_usage, pro.memory);
        }

        left_tree.set_model(&list_store.get_model().unwrap());
        left_tree.set_headers_visible(true);
        scroll.add(&left_tree);
        let mut vertical_layout = gtk::Box::new(gtk::Orientation::Vertical, 0).unwrap();

        left_tree.connect_cursor_changed(move |tree_view| {
            match tree_view.get_selection() {
                Some(selection) => {
                    let model = tree_view.get_model().unwrap();
                    let mut iter = gtk::TreeIter::new();

                    if selection.get_selected(&model, &mut iter) {
                        let pid = model.get_value(&iter, 0).get_string();
                        let mut tmp = current_pid1.borrow_mut();
                        *tmp = pid;
                    }
                    (*kill_button1.borrow_mut()).set_sensitive((*current_pid.borrow()).is_some());
                }
                None => {
                    let mut tmp = current_pid1.borrow_mut();
                    *tmp = None;
                }
            }
        });
        (*kill_button.borrow_mut()).set_sensitive(false);

        vertical_layout.add(&scroll);
        vertical_layout.add(&(*kill_button.borrow_mut()));
        Procs {
            left_tree: left_tree,
            scroll: scroll,
            current_pid: current_pid2.clone(),
            kill_button: kill_button,
            vertical_layout: vertical_layout,
            list_store: list_store
        }
    }
}

fn append_column(title: &str, v: &mut Vec<gtk::TreeViewColumn>) {
    let l = v.len();
    let renderer = gtk::CellRendererText::new().unwrap();

    v.push(gtk::TreeViewColumn::new().unwrap());
    let tmp = v.get_mut(l).unwrap();

    tmp.set_title(title);
    tmp.pack_start(&renderer, true);
    tmp.add_attribute(&renderer, "text", l as i32);
}

fn create_and_fill_model(list_store: &mut gtk::ListStore, pid: i64, name: &str, cpu: f32, memory: u64) {
    if name.len() < 1 {
        return;
    }
    let mut top_level = gtk::TreeIter::new();

    list_store.append(&mut top_level);
    list_store.set_string(&top_level, 0, &format!("{}", pid));
    list_store.set_string(&top_level, 1, name);
    list_store.set_string(&top_level, 2, &format!("{}", cpu));
    list_store.set_string(&top_level, 3, &format!("{}", memory));
}

fn update_window(w: &mut (&mut gtk::ListStore, Rc<RefCell<sysinfo::System>>, Rc<RefCell<DisplaySysInfo>>)) -> i32 {
    let mut model = w.0.get_model().unwrap();
    let mut iter = gtk::TreeIter::new();

    (*w.1.borrow_mut()).refresh();
    let mut entries : VecMap<Processus> = ((*w.1.borrow()).get_processus_list()).clone();
    let mut nb = model.iter_n_children(None);

    let sys = w.1.clone();
    (*w.2.borrow_mut()).update_ram_display(sys.clone());
    (*w.2.borrow_mut()).update_process_display(sys);

    let mut i = 0;
    while i < nb {
        if model.iter_nth_child(&mut iter, None, i) {
            let pid : i64 = i64::from_str(&model.get_value(&iter, 0).get_string().unwrap()).unwrap();
            let mut to_delete = false;

            match entries.get(&(pid as usize)) {
                Some(p) => {
                    //w.0.set_string(&iter, 1, &p.name);
                    w.0.set_string(&iter, 2, &format!("{}", p.cpu_usage));
                    w.0.set_string(&iter, 3, &format!("{}", p.memory));
                    to_delete = true;
                }
                None => {
                    w.0.remove(&iter);
                }
            }
            if to_delete {
                entries.remove(&(pid as usize));
                nb = model.iter_n_children(None);
                i += 1;
            }
        } else {
            i += 1;
        }
    }
    for (_, pro) in entries {
        create_and_fill_model(&mut w.0, pro.pid, &pro.name, pro.cpu_usage, pro.memory);
    }
    1
}

struct DisplaySysInfo {
    procs : Rc<RefCell<Vec<gtk::ProgressBar>>>,
    ram : Rc<RefCell<gtk::ProgressBar>>,
    swap : Rc<RefCell<gtk::ProgressBar>>,
    vertical_layout : gtk::Box
}

impl DisplaySysInfo {
    pub fn new(sys1: Rc<RefCell<sysinfo::System>>) -> DisplaySysInfo {
        let mut tmp = DisplaySysInfo {
            procs: Rc::new(RefCell::new(Vec::new())),
            ram: Rc::new(RefCell::new(gtk::ProgressBar::new().unwrap())),
            swap: Rc::new(RefCell::new(gtk::ProgressBar::new().unwrap())),
            vertical_layout: gtk::Box::new(gtk::Orientation::Vertical, 0).unwrap()
        };

        let sys2 = sys1.clone();
        let mut v = tmp.procs.clone();

        (*tmp.ram.borrow_mut()).set_show_text(true);
        (*tmp.swap.borrow_mut()).set_show_text(true);

        tmp.vertical_layout.set_spacing(5);
        let mut i = 1;
        let mut total = false;

        tmp.vertical_layout.pack_start(&gtk::Label::new("Memory usage").unwrap(), false, false, 15);
        tmp.vertical_layout.add(&(*tmp.ram.borrow()));
        tmp.vertical_layout.pack_start(&gtk::Label::new("Swap usage").unwrap(), false, false, 15);
        tmp.vertical_layout.add(&(*tmp.swap.borrow()));
        tmp.vertical_layout.pack_start(&gtk::Label::new("Process usage").unwrap(), false, false, 15);
        for pro in (*sys1.borrow()).get_process_list() {
            if total {
                (*v.borrow_mut()).push(gtk::ProgressBar::new().unwrap());
                let p : &gtk::ProgressBar = &(*v.borrow())[i - 1];
                let l = gtk::Label::new(&format!("{}", i)).unwrap();
                let horizontal_layout = gtk::Box::new(gtk::Orientation::Horizontal, 0).unwrap();

                p.set_text(&format!("{:.2} %", pro.get_cpu_usage() * 100.));
                p.set_show_text(true);
                p.set_fraction(pro.get_cpu_usage() as f64);
                horizontal_layout.pack_start(&l, false, false, 5);
                horizontal_layout.pack_start(p, true, true, 5);
                tmp.vertical_layout.add(&horizontal_layout);
                i += 1;
            } else {
                total = true;
            }
        }
        tmp.update_ram_display(sys2);
        tmp
    }

    pub fn update_ram_display(&mut self, sys: Rc<RefCell<sysinfo::System>>) {
        let total = (*sys.borrow()).get_total_memory();
        let used = (*sys.borrow()).get_free_memory();
        let disp = if total < 100000 {
            format!("{} / {}B", used, total)
        } else if total < 10000000 {
            format!("{} / {}KB", used / 1000, total / 1000)
        } else if total < 10000000000 {
            format!("{} / {}MB", used / 1000000, total / 1000000)
        } else {
            format!("{} / {}GB", used / 1000000000, total / 1000000000)
        };

        (*self.ram.borrow_mut()).set_text(&disp);
        (*self.ram.borrow_mut()).set_fraction(used as f64 / total as f64);

        let total = (*sys.borrow()).get_total_swap();
        let used = total - (*sys.borrow()).get_free_swap();
        let disp = if total < 100000 {
            format!("{} / {}B", used, total)
        } else if total < 10000000 {
            format!("{} / {}KB", used / 1000, total / 1000)
        } else if total < 10000000000 {
            format!("{} / {}MB", used / 1000000, total / 1000000)
        } else {
            format!("{} / {}GB", used / 1000000000, total / 1000000000)
        };

        (*self.swap.borrow_mut()).set_text(&disp);
        (*self.swap.borrow_mut()).set_fraction(used as f64 / total as f64);
    }

    pub fn update_process_display(&mut self, sys: Rc<RefCell<sysinfo::System>>) {
        let v = &*self.procs.borrow_mut();
        let mut total = false;
        let mut i = 0;
        for pro in (*sys.borrow()).get_process_list() {
            if total {
                v[i].set_text(&format!("{:.1} %", pro.get_cpu_usage() * 100.));
                v[i].set_show_text(true);
                v[i].set_fraction(pro.get_cpu_usage() as f64);
                i += 1;
            } else {
                total = true;
            }
        }
    }
}

fn main() {
    gtk::init();

    let mut window = gtk::Window::new(gtk::WindowType::TopLevel).unwrap();
    let mut sys : Rc<RefCell<sysinfo::System>> = Rc::new(RefCell::new(sysinfo::System::new()));
    let mut note = NoteBook::new();
    (*sys.borrow_mut()).refresh();
    let mut procs = Procs::new((*sys.borrow()).get_processus_list());
    let mut current_pid2 = procs.current_pid.clone();
    let mut sys1 = sys.clone();
    let mut sys2 = sys.clone();

    window.set_title("Processus viewer");
    window.set_window_position(gtk::WindowPosition::Center);

    window.connect_delete_event(|_, _| {
        gtk::main_quit();
        Inhibit(true)
    });

    (*procs.kill_button.borrow_mut()).connect_clicked(move |_| {
        let tmp = (*current_pid2.borrow_mut()).is_some() ;

        if tmp {
            let s = (*current_pid2.borrow()).clone();
            match (*sys.borrow_mut()).get_processus(i64::from_str(&s.unwrap()).unwrap()) {
                Some(p) => {
                    p.kill(Signal::Kill);
                },
                None => {}
            };
        }
    });

    let mut display_tab = Rc::new(RefCell::new(DisplaySysInfo::new(sys2)));

    glib::timeout::add(1500, update_window, &mut (&mut procs.list_store, sys1.clone(), display_tab.clone()));
    //window.add(&vertical_layout);
    note.create_tab("Processus list", &procs.vertical_layout);
    //let t = gtk::Button::new_with_label("test").unwrap();
    note.create_tab("System usage", &(*display_tab.borrow()).vertical_layout);
    window.add(&note.notebook);
    window.show_all();
    gtk::main();
}
<|endoftext|>


<commit_before>#![feature(slicing_syntax)]

extern crate test;
extern crate time;

use std::io::{stdio, File};
use std::os;

enum Direction {
    South,
    SouthEast,
    SouthWest,
    West,
}

static DIRECTIONS: &'static [Direction] = &[South, SouthEast, SouthWest, West];

impl Direction {
    fn step(self) -> (uint, uint) {
        match self {
            South => (1, 0),
            SouthEast => (1, -1),
            SouthWest => (1, 1),
            West => (0, 1),
        }
    }
}

struct Grid {
    data: Vec<u32>,
    size: uint,
}

impl Grid {
    fn from_str(grid: &str) -> Grid {
        let size = grid.lines().count();

        assert!(grid.lines().all(|line| line.words().count() == size), "Grid is not square");

        let mut data = Vec::with_capacity(size * size);
        for line in grid.lines() {
            for word in line.words() {
                data.push(from_str(word).unwrap());
            }
        }

        Grid {
            data: data,
            size: size,
        }
    }

    fn get(&self, row: uint, col: uint) -> Option<u32> {
        if row < self.size && col < self.size {
            Some(unsafe { *self.data[].unsafe_get(row * self.size + col) })
        } else {
            None
        }
    }

    fn product(
        &self,
        (row, col): (uint, uint),
        direction: Direction,
        window: uint
    ) -> Option<u32> {
        let (row_step, col_step) = direction.step();
        let mut p = match self.get(row, col) {
            Some(elem) => elem,
            None => return None,
        };

        for i in range(1, window) {
            match self.get(row + i * row_step, col + i * col_step) {
                Some(elem) => p *= elem,
                None => return None,
            }
        }

        Some(p)
    }
}

fn solution(grid: &str) -> u32 {
    let grid = Grid::from_str(grid);

    range(0, grid.size).fold(0, |max, row| {
        range(0, grid.size).fold(max, |max, col| {
            DIRECTIONS.iter().fold(max, |max, &dir| {
                match grid.product((row, col), dir, 4) {
                    None => max,
                    Some(p) => if p > max { p } else { max },
                }
            })
        })
    })
}

fn main() {
    let contents = File::open(&Path::new("011.txt")).read_to_string().unwrap();
    let contents = contents[];

    match os::args()[] {
        [_, ref flag] if flag[] == "-a" => return println!("{}", solution(contents)),
        _ => {},
    }

    for line in stdio::stdin().lines() {
        let iters: u64 = from_str(line.unwrap()[].trim()).unwrap();

        let start = time::precise_time_ns();
        for _ in range(0, iters) {
            test::black_box(solution(contents));
        }
        let end = time::precise_time_ns();

        println!("{}", end - start);
    }
}
<commit_msg>fix(011.rs): enums are now namespaced<commit_after>#![feature(slicing_syntax)]

extern crate test;
extern crate time;

use std::io::{stdio, File};
use std::os;

use Direction::{South, SouthEast, SouthWest, West};

enum Direction {
    South,
    SouthEast,
    SouthWest,
    West,
}

static DIRECTIONS: &'static [Direction] = &[South, SouthEast, SouthWest, West];

impl Direction {
    fn step(self) -> (uint, uint) {
        match self {
            South => (1, 0),
            SouthEast => (1, -1),
            SouthWest => (1, 1),
            West => (0, 1),
        }
    }
}

struct Grid {
    data: Vec<u32>,
    size: uint,
}

impl Grid {
    fn from_str(grid: &str) -> Grid {
        let size = grid.lines().count();

        assert!(grid.lines().all(|line| line.words().count() == size), "Grid is not square");

        let mut data = Vec::with_capacity(size * size);
        for line in grid.lines() {
            for word in line.words() {
                data.push(from_str(word).unwrap());
            }
        }

        Grid {
            data: data,
            size: size,
        }
    }

    fn get(&self, row: uint, col: uint) -> Option<u32> {
        if row < self.size && col < self.size {
            Some(unsafe { *self.data[].unsafe_get(row * self.size + col) })
        } else {
            None
        }
    }

    fn product(
        &self,
        (row, col): (uint, uint),
        direction: Direction,
        window: uint
    ) -> Option<u32> {
        let (row_step, col_step) = direction.step();
        let mut p = match self.get(row, col) {
            Some(elem) => elem,
            None => return None,
        };

        for i in range(1, window) {
            match self.get(row + i * row_step, col + i * col_step) {
                Some(elem) => p *= elem,
                None => return None,
            }
        }

        Some(p)
    }
}

fn solution(grid: &str) -> u32 {
    let grid = Grid::from_str(grid);

    range(0, grid.size).fold(0, |max, row| {
        range(0, grid.size).fold(max, |max, col| {
            DIRECTIONS.iter().fold(max, |max, &dir| {
                match grid.product((row, col), dir, 4) {
                    None => max,
                    Some(p) => if p > max { p } else { max },
                }
            })
        })
    })
}

fn main() {
    let contents = File::open(&Path::new("011.txt")).read_to_string().unwrap();
    let contents = contents[];

    match os::args()[] {
        [_, ref flag] if flag[] == "-a" => return println!("{}", solution(contents)),
        _ => {},
    }

    for line in stdio::stdin().lines() {
        let iters: u64 = from_str(line.unwrap()[].trim()).unwrap();

        let start = time::precise_time_ns();
        for _ in range(0, iters) {
            test::black_box(solution(contents));
        }
        let end = time::precise_time_ns();

        println!("{}", end - start);
    }
}
<|endoftext|>


<commit_before>extern crate test;
extern crate time;

use std::os::args;
use test::black_box;
use time::precise_time_ns;

#[deriving(FromPrimitive,PartialEq,TotalEq)]
enum Day {
    Monday, Tuesday, Wednesday, Thursday, Friday, Saturday, Sunday,
}

impl Day {
    fn advance(&self, days: uint) -> Day {
        FromPrimitive::from_uint((*self as uint + days) % 7).unwrap()
    }
}

enum Month {
    January, February, March, April, May, June, July, August, September,
    October, November, December,
}

static MONTHS: [Month, ..12] = [January, February, March, April, May, June,
                                July, August, September, October, November,
                                December];

impl Month {
    fn days(&self, year: Year) -> uint {
        match *self {
            January | March | May | July | August | October | December => 31,
            April | June | September | November => 30,
            February => if year.is_leap() { 29 } else { 28 },
        }
    }
}

type Year = uint;

trait Leap {
    fn is_leap(&self) -> bool;
}

impl Leap for Year {
    fn is_leap(&self) -> bool {
        if *self % 400 == 0 {
            true
        } else if *self % 100 == 0 {
            false
        } else if *self % 4 == 0 {
            true
        } else {
            false
        }
    }
}

#[inline]
fn f() -> u64 {
    let mut count = 0;
    let mut today = Monday;

    for year in range(1900 as Year, 2001) {
        for month in MONTHS.iter() {
            today = today.advance(month.days(year));

            if year != 1900 && today == Sunday {
                count += 1;
            }
        }
    }

    count
}

fn main() {
    match args().as_slice() {
        [_] => {
            println!("{}", f());
        },
        [_, ref iters] => {
            let iters: u64 = from_str(iters.as_slice()).unwrap();

            let start = precise_time_ns();
            for _ in range(0, iters) {
                black_box(f());
            }
            let end = precise_time_ns();

            println!("{}", end - start);
        },
        _ => unreachable!(),
    }
}
<commit_msg>change TotalEq back to Eq<commit_after>extern crate test;
extern crate time;

use std::os::args;
use test::black_box;
use time::precise_time_ns;

#[deriving(FromPrimitive,PartialEq,Eq)]
enum Day {
    Monday, Tuesday, Wednesday, Thursday, Friday, Saturday, Sunday,
}

impl Day {
    fn advance(&self, days: uint) -> Day {
        FromPrimitive::from_uint((*self as uint + days) % 7).unwrap()
    }
}

enum Month {
    January, February, March, April, May, June, July, August, September,
    October, November, December,
}

static MONTHS: [Month, ..12] = [January, February, March, April, May, June,
                                July, August, September, October, November,
                                December];

impl Month {
    fn days(&self, year: Year) -> uint {
        match *self {
            January | March | May | July | August | October | December => 31,
            April | June | September | November => 30,
            February => if year.is_leap() { 29 } else { 28 },
        }
    }
}

type Year = uint;

trait Leap {
    fn is_leap(&self) -> bool;
}

impl Leap for Year {
    fn is_leap(&self) -> bool {
        if *self % 400 == 0 {
            true
        } else if *self % 100 == 0 {
            false
        } else if *self % 4 == 0 {
            true
        } else {
            false
        }
    }
}

#[inline]
fn f() -> u64 {
    let mut count = 0;
    let mut today = Monday;

    for year in range(1900 as Year, 2001) {
        for month in MONTHS.iter() {
            today = today.advance(month.days(year));

            if year != 1900 && today == Sunday {
                count += 1;
            }
        }
    }

    count
}

fn main() {
    match args().as_slice() {
        [_] => {
            println!("{}", f());
        },
        [_, ref iters] => {
            let iters: u64 = from_str(iters.as_slice()).unwrap();

            let start = precise_time_ns();
            for _ in range(0, iters) {
                black_box(f());
            }
            let end = precise_time_ns();

            println!("{}", end - start);
        },
        _ => unreachable!(),
    }
}
<|endoftext|>


<commit_before>//! A small library meant to be used as a build dependency with Cargo for easily
//! integrating [ISPC](https://ispc.github.io/) code into Rust projects. The
//! `ispc_rt` crate is specifically targetted at linking with a previously
//! compiled ISPC library and generated bindings (built with `ispc_compile`),
//! to allow end users to link ISPC code without needing the ISPC compiler or clang.
//!
//! This crate also includes the various runtime components for the ISPC
//! language, including the parallel task system and performance instrumentation.
//!

#![allow(dead_code)]

extern crate libc;
extern crate aligned_alloc;
extern crate num_cpus;

pub mod task;
pub mod exec;
pub mod instrument;

use std::mem;
use std::env;
use std::sync::{Once, Arc};
use std::ffi::CStr;
use std::path::{Path, PathBuf};

pub use task::ISPCTaskFn;
pub use exec::{TaskSystem, Parallel};
pub use instrument::{Instrument, SimpleInstrument};

/// Convenience macro for generating the module to hold the raw/unsafe ISPC bindings.
///
/// In addition to building the library with ISPC we use rust-bindgen to generate
/// a rust module containing bindings to the functions exported from ISPC. These
/// can be imported by passing the name of your library to the `ispc_module` macro.
///
/// # Example
///
/// ```ignore
/// #[macro_use]
/// extern crate ispc_rt;
///
/// // Functions exported from foo will be callable under foo::*
/// ispc_module!(foo);
/// ```
#[macro_export]
macro_rules! ispc_module {
    ($lib:ident) => (
        include!(concat!(env!("ISPC_OUT_DIR"), "/", stringify!($lib), ".rs"));
    )
}

/// A `PackagedModule` refers to an ISPC module which was previously
/// built using `ispc_compile`, and is now distributed with
/// the crate.
pub struct PackagedModule {
    path: Option<PathBuf>,
    lib: String,
}

impl PackagedModule {
    /// Create a new `PackagedModule` to link against the previously compiled
    /// library named `lib`. As in `ispc_compile`, the library name should not
    /// have any prefix or suffix. For example, instead of `libexample.a` or
    /// `example.lib`, simple pass `example`
    pub fn new(lib: &str) -> PackagedModule {
        PackagedModule {path: None, lib: lib.to_owned()}
    }
    /// Specify the path to search for the packaged ISPC libraries and bindings
    pub fn lib_path<P: AsRef<Path>>(&mut self, path: P) -> &mut PackagedModule {
        self.path = Some(path.as_ref().to_path_buf());
        self
    }
    /// Link with a previously built ISPC library packaged with the crate
    pub fn link(&self) {
        let libfile = self.lib.clone() + &env::var("HOST").unwrap();
        let bindgen_file = self.lib.clone() + ".rs";
        println!("cargo:rerun-if-changed={}", libfile);
        println!("cargo:rerun-if-changed={}", bindgen_file);
        println!("cargo:rustc-link-lib=static={}", libfile);

        let path = self.get_lib_path();
        println!("cargo:rustc-link-search=native={}", path.display());
        println!("cargo:rustc-env=ISPC_OUT_DIR={}", path.display());
    }
    /// Returns the user-set output directory if they've set one, otherwise
    /// returns env("OUT_DIR")
    fn get_lib_path(&self) -> PathBuf {
        let p = self.path.clone().unwrap_or_else(|| {
            env::var_os("OUT_DIR").map(PathBuf::from).unwrap()
        });
        if p.is_relative() {
            env::current_dir().unwrap().join(p)
        } else {
            p
        }
    }
}

static mut TASK_SYSTEM: Option<&'static dyn TaskSystem> = None;
static TASK_INIT: Once = Once::new();

static mut INSTRUMENT: Option<&'static dyn Instrument> = None;
static INSTRUMENT_INIT: Once = Once::new();

/// If you have implemented your own task system you can provide it for use instead
/// of the default threaded one. This must be done prior to calling ISPC code which
/// spawns tasks otherwise the task system will have already been initialized to
/// `Parallel`, which you can also see as an example for implementing a task system.
///
/// Use the function to do any extra initialization for your task system. Note that
/// the task system will be leaked and not destroyed until the program exits and the
/// memory space is cleaned up.
pub fn set_task_system<F: FnOnce() -> Arc<dyn TaskSystem>>(f: F) {
    TASK_INIT.call_once(|| {
        let task_sys = f();
        unsafe {
            let s = &*task_sys as *const (dyn TaskSystem + 'static);
            mem::forget(task_sys);
            TASK_SYSTEM = Some(&*s);
        }
    });
}

fn get_task_system() -> &'static dyn TaskSystem {
    // TODO: This is a bit nasty, but I'm not sure on a nicer solution. Maybe something that
    // would let the user register the desired (or default) task system? But if
    // mutable statics can't have destructors we still couldn't have an Arc or Box to something?
    TASK_INIT.call_once(|| {
        unsafe {
            let task_sys = Parallel::new() as Arc<dyn TaskSystem>;
            let s = &*task_sys as *const (dyn TaskSystem + 'static);
            mem::forget(task_sys);
            TASK_SYSTEM = Some(&*s);
        }
    });
    unsafe { TASK_SYSTEM.unwrap() }
}

/// If you have implemented your own instrument for logging ISPC performance
/// data you can use this function to provide it for use instead of the
/// default one. This function **must** be called before calling into ISPC code,
/// otherwise the instrumenter will already be set to the default.
pub fn set_instrument<F: FnOnce() -> Arc<dyn Instrument>>(f: F) {
    INSTRUMENT_INIT.call_once(|| {
        let instrument = f();
        unsafe {
            let s = &*instrument as *const (dyn Instrument + 'static);
            mem::forget(instrument);
            INSTRUMENT = Some(&*s);
        }
    });
}

/// Print out a summary of performace data gathered from instrumenting ISPC.
/// Must enable instrumenting to have this record and print data, see
/// `Config::instrument`.
pub fn print_instrumenting_summary() {
    get_instrument().print_summary();
}

fn get_instrument() -> &'static dyn Instrument {
    // TODO: This is a bit nasty, like above
    INSTRUMENT_INIT.call_once(|| {
        unsafe {
            let instrument = Arc::new(SimpleInstrument) as Arc<dyn Instrument>;
            let s = &*instrument as *const (dyn Instrument + 'static);
            mem::forget(instrument);
            INSTRUMENT = Some(&*s);
        }
    });
    unsafe { INSTRUMENT.unwrap() }
}

#[allow(non_snake_case)]
#[doc(hidden)]
#[no_mangle]
pub unsafe extern "C" fn ISPCAlloc(handle_ptr: *mut *mut libc::c_void, size: i64,
                                   align: i32) -> *mut libc::c_void {
    get_task_system().alloc(handle_ptr, size, align)
}

#[allow(non_snake_case)]
#[doc(hidden)]
#[no_mangle]
pub unsafe extern "C" fn ISPCLaunch(handle_ptr: *mut *mut libc::c_void, f: *mut libc::c_void,
                                    data: *mut libc::c_void, count0: libc::c_int,
                                    count1: libc::c_int, count2: libc::c_int) {
    let task_fn: ISPCTaskFn = mem::transmute(f);
    get_task_system().launch(handle_ptr, task_fn, data, count0 as i32, count1 as i32, count2 as i32);
}

#[allow(non_snake_case)]
#[doc(hidden)]
#[no_mangle]
pub unsafe extern "C" fn ISPCSync(handle: *mut libc::c_void){
    get_task_system().sync(handle);
}

#[allow(non_snake_case)]
#[doc(hidden)]
#[no_mangle]
pub unsafe extern "C" fn ISPCInstrument(cfile: *const libc::c_char, cnote: *const libc::c_char,
                                        line: libc::c_int, mask: u64) {

    let file_name = CStr::from_ptr(cfile);
    let note = CStr::from_ptr(cnote);
    let active_count = (mask as u64).count_ones();
    get_instrument().instrument(file_name, note, line as i32, mask as u64, active_count);
}

<commit_msg>Fix Cargo change detection in the runtime<commit_after>//! A small library meant to be used as a build dependency with Cargo for easily
//! integrating [ISPC](https://ispc.github.io/) code into Rust projects. The
//! `ispc_rt` crate is specifically targetted at linking with a previously
//! compiled ISPC library and generated bindings (built with `ispc_compile`),
//! to allow end users to link ISPC code without needing the ISPC compiler or clang.
//!
//! This crate also includes the various runtime components for the ISPC
//! language, including the parallel task system and performance instrumentation.
//!

#![allow(dead_code)]

extern crate libc;
extern crate aligned_alloc;
extern crate num_cpus;

pub mod task;
pub mod exec;
pub mod instrument;

use std::mem;
use std::env;
use std::sync::{Once, Arc};
use std::ffi::CStr;
use std::path::{Path, PathBuf};

pub use task::ISPCTaskFn;
pub use exec::{TaskSystem, Parallel};
pub use instrument::{Instrument, SimpleInstrument};

/// Convenience macro for generating the module to hold the raw/unsafe ISPC bindings.
///
/// In addition to building the library with ISPC we use rust-bindgen to generate
/// a rust module containing bindings to the functions exported from ISPC. These
/// can be imported by passing the name of your library to the `ispc_module` macro.
///
/// # Example
///
/// ```ignore
/// #[macro_use]
/// extern crate ispc_rt;
///
/// // Functions exported from foo will be callable under foo::*
/// ispc_module!(foo);
/// ```
#[macro_export]
macro_rules! ispc_module {
    ($lib:ident) => (
        include!(concat!(env!("ISPC_OUT_DIR"), "/", stringify!($lib), ".rs"));
    )
}

/// A `PackagedModule` refers to an ISPC module which was previously
/// built using `ispc_compile`, and is now distributed with
/// the crate.
pub struct PackagedModule {
    path: Option<PathBuf>,
    lib: String,
}

impl PackagedModule {
    /// Create a new `PackagedModule` to link against the previously compiled
    /// library named `lib`. As in `ispc_compile`, the library name should not
    /// have any prefix or suffix. For example, instead of `libexample.a` or
    /// `example.lib`, simple pass `example`
    pub fn new(lib: &str) -> PackagedModule {
        PackagedModule {path: None, lib: lib.to_owned()}
    }
    /// Specify the path to search for the packaged ISPC libraries and bindings
    pub fn lib_path<P: AsRef<Path>>(&mut self, path: P) -> &mut PackagedModule {
        self.path = Some(path.as_ref().to_path_buf());
        self
    }
    /// Link with a previously built ISPC library packaged with the crate
    pub fn link(&self) {
        let path = self.get_lib_path();
        let libfile = self.lib.clone() + &env::var("TARGET").unwrap();
        let bindgen_file = self.lib.clone() + ".rs";

        println!("cargo:rustc-link-lib=static={}", libfile);
        println!("cargo:rerun-if-changed={}", path.join(get_lib_filename(&libfile)).display());
        println!("cargo:rerun-if-changed={}", path.join(bindgen_file).display());
        println!("cargo:rustc-link-search=native={}", path.display());
        println!("cargo:rustc-env=ISPC_OUT_DIR={}", path.display());
    }
    /// Returns the user-set output directory if they've set one, otherwise
    /// returns env("OUT_DIR")
    fn get_lib_path(&self) -> PathBuf {
        let p = self.path.clone().unwrap_or_else(|| {
            env::var_os("OUT_DIR").map(PathBuf::from).unwrap()
        });
        if p.is_relative() {
            env::current_dir().unwrap().join(p)
        } else {
            p
        }
    }
}

fn get_lib_filename(libfile: &str) -> String {
    if libfile.contains("windows") {
        format!("{}.lib", libfile)
    } else {
        format!("lib{}.a", libfile)
    }
}

static mut TASK_SYSTEM: Option<&'static dyn TaskSystem> = None;
static TASK_INIT: Once = Once::new();

static mut INSTRUMENT: Option<&'static dyn Instrument> = None;
static INSTRUMENT_INIT: Once = Once::new();

/// If you have implemented your own task system you can provide it for use instead
/// of the default threaded one. This must be done prior to calling ISPC code which
/// spawns tasks otherwise the task system will have already been initialized to
/// `Parallel`, which you can also see as an example for implementing a task system.
///
/// Use the function to do any extra initialization for your task system. Note that
/// the task system will be leaked and not destroyed until the program exits and the
/// memory space is cleaned up.
pub fn set_task_system<F: FnOnce() -> Arc<dyn TaskSystem>>(f: F) {
    TASK_INIT.call_once(|| {
        let task_sys = f();
        unsafe {
            let s = &*task_sys as *const (dyn TaskSystem + 'static);
            mem::forget(task_sys);
            TASK_SYSTEM = Some(&*s);
        }
    });
}

fn get_task_system() -> &'static dyn TaskSystem {
    // TODO: This is a bit nasty, but I'm not sure on a nicer solution. Maybe something that
    // would let the user register the desired (or default) task system? But if
    // mutable statics can't have destructors we still couldn't have an Arc or Box to something?
    TASK_INIT.call_once(|| {
        unsafe {
            let task_sys = Parallel::new() as Arc<dyn TaskSystem>;
            let s = &*task_sys as *const (dyn TaskSystem + 'static);
            mem::forget(task_sys);
            TASK_SYSTEM = Some(&*s);
        }
    });
    unsafe { TASK_SYSTEM.unwrap() }
}

/// If you have implemented your own instrument for logging ISPC performance
/// data you can use this function to provide it for use instead of the
/// default one. This function **must** be called before calling into ISPC code,
/// otherwise the instrumenter will already be set to the default.
pub fn set_instrument<F: FnOnce() -> Arc<dyn Instrument>>(f: F) {
    INSTRUMENT_INIT.call_once(|| {
        let instrument = f();
        unsafe {
            let s = &*instrument as *const (dyn Instrument + 'static);
            mem::forget(instrument);
            INSTRUMENT = Some(&*s);
        }
    });
}

/// Print out a summary of performace data gathered from instrumenting ISPC.
/// Must enable instrumenting to have this record and print data, see
/// `Config::instrument`.
pub fn print_instrumenting_summary() {
    get_instrument().print_summary();
}

fn get_instrument() -> &'static dyn Instrument {
    // TODO: This is a bit nasty, like above
    INSTRUMENT_INIT.call_once(|| {
        unsafe {
            let instrument = Arc::new(SimpleInstrument) as Arc<dyn Instrument>;
            let s = &*instrument as *const (dyn Instrument + 'static);
            mem::forget(instrument);
            INSTRUMENT = Some(&*s);
        }
    });
    unsafe { INSTRUMENT.unwrap() }
}

#[allow(non_snake_case)]
#[doc(hidden)]
#[no_mangle]
pub unsafe extern "C" fn ISPCAlloc(handle_ptr: *mut *mut libc::c_void, size: i64,
                                   align: i32) -> *mut libc::c_void {
    get_task_system().alloc(handle_ptr, size, align)
}

#[allow(non_snake_case)]
#[doc(hidden)]
#[no_mangle]
pub unsafe extern "C" fn ISPCLaunch(handle_ptr: *mut *mut libc::c_void, f: *mut libc::c_void,
                                    data: *mut libc::c_void, count0: libc::c_int,
                                    count1: libc::c_int, count2: libc::c_int) {
    let task_fn: ISPCTaskFn = mem::transmute(f);
    get_task_system().launch(handle_ptr, task_fn, data, count0 as i32, count1 as i32, count2 as i32);
}

#[allow(non_snake_case)]
#[doc(hidden)]
#[no_mangle]
pub unsafe extern "C" fn ISPCSync(handle: *mut libc::c_void){
    get_task_system().sync(handle);
}

#[allow(non_snake_case)]
#[doc(hidden)]
#[no_mangle]
pub unsafe extern "C" fn ISPCInstrument(cfile: *const libc::c_char, cnote: *const libc::c_char,
                                        line: libc::c_int, mask: u64) {

    let file_name = CStr::from_ptr(cfile);
    let note = CStr::from_ptr(cnote);
    let active_count = (mask as u64).count_ones();
    get_instrument().instrument(file_name, note, line as i32, mask as u64, active_count);
}

<|endoftext|>


<commit_before>extern crate odbc;
use odbc::*;

#[test]
fn list_tables() {

    let mut env = Environment::new().unwrap();
    let mut ds = DataSource::with_dsn_and_credentials(&mut env, "PostgreSQL", "postgres", "")
        .unwrap();
    // scope is required (for now) to close statement before disconnecting
    {
        let statement = Statement::with_tables(&mut ds).unwrap();
        assert_eq!(statement.num_result_cols().unwrap(), 5);
    }
    ds.disconnect().unwrap();
}

#[test]
fn test_connection() {

    let mut environment = Environment::new().expect("Environment can be created");
    let mut conn =
        DataSource::with_dsn_and_credentials(&mut environment, "PostgreSQL", "postgres", "")
            .expect("Could not connect");

    assert!(!conn.read_only().unwrap());
    conn.disconnect().unwrap();
}

#[test]
fn list_drivers() {
    let environment = Environment::new();
    let drivers = environment.expect("Environment can be created")
        .drivers()
        .expect("Drivers can be iterated over");
    println!("{:?}", drivers);

    let expected = ["PostgreSQL ANSI", "PostgreSQL Unicode", "SQLite", "SQLite3"];
    assert!(drivers.iter().map(|d| &d.description).eq(expected.iter()));
}

#[test]
fn list_data_sources() {
    let environment = Environment::new();
    let sources = environment.expect("Environment can be created")
        .data_sources()
        .expect("Data sources can be iterated over");
    println!("{:?}", sources);

    let expected = [DataSourceInfo {
                        server_name: "PostgreSQL".to_owned(),
                        description: "PostgreSQL Unicode".to_owned(),
                    }];
    assert!(sources.iter().eq(expected.iter()));
}

#[test]
fn list_user_data_sources() {
    let environment = Environment::new();
    let sources = environment.expect("Environment can be created")
        .user_data_sources()
        .expect("Data sources can be iterated over");
    println!("{:?}", sources);

    let expected = [DataSourceInfo {
                        server_name: "PostgreSQL".to_owned(),
                        description: "PostgreSQL Unicode".to_owned(),
                    }];
    assert!(sources.iter().eq(expected.iter()));
}

#[test]
fn list_system_data_sources() {
    let environment = Environment::new();
    let sources = environment.expect("Environment can be created")
        .system_data_sources()
        .expect("Data sources can be iterated over");
    println!("{:?}", sources);

    let expected: [DataSourceInfo; 0] = [];
    assert!(sources.iter().eq(expected.iter()));
}

<commit_msg>fix function sequence errors in tests<commit_after>extern crate odbc;
use odbc::*;

#[test]
fn list_tables() {

    let mut env = Environment::new().unwrap();
    env.set_odbc_version_3();
    let mut ds = DataSource::with_dsn_and_credentials(&mut env, "PostgreSQL", "postgres", "")
        .unwrap();
    // scope is required (for now) to close statement before disconnecting
    {
        let statement = Statement::with_tables(&mut ds).unwrap();
        assert_eq!(statement.num_result_cols().unwrap(), 5);
    }
    ds.disconnect().unwrap();
}

#[test]
fn test_connection() {

    let mut environment = Environment::new().expect("Environment can be created");
    environment.set_odbc_version_3();
    let mut conn =
        DataSource::with_dsn_and_credentials(&mut environment, "PostgreSQL", "postgres", "")
            .expect("Could not connect");

    assert!(!conn.read_only().unwrap());
    conn.disconnect().unwrap();
}

#[test]
fn list_drivers() {
    let mut environment = Environment::new().unwrap();
    environment.set_odbc_version_3();
    let drivers = environment.drivers()
        .expect("Drivers can be iterated over");
    println!("{:?}", drivers);

    let expected = ["PostgreSQL ANSI", "PostgreSQL Unicode", "SQLite", "SQLite3"];
    assert!(drivers.iter().map(|d| &d.description).eq(expected.iter()));
}

#[test]
fn list_data_sources() {
    let mut environment = Environment::new().unwrap();
    environment.set_odbc_version_3();
    let sources = environment.data_sources()
        .expect("Data sources can be iterated over");
    println!("{:?}", sources);

    let expected = [DataSourceInfo {
                        server_name: "PostgreSQL".to_owned(),
                        description: "PostgreSQL Unicode".to_owned(),
                    }];
    assert!(sources.iter().eq(expected.iter()));
}

#[test]
fn list_user_data_sources() {
    let mut environment = Environment::new().unwrap();
    environment.set_odbc_version_3();
    let sources = environment.user_data_sources()
        .expect("Data sources can be iterated over");
    println!("{:?}", sources);

    let expected = [DataSourceInfo {
                        server_name: "PostgreSQL".to_owned(),
                        description: "PostgreSQL Unicode".to_owned(),
                    }];
    assert!(sources.iter().eq(expected.iter()));
}

#[test]
fn list_system_data_sources() {
    let mut environment = Environment::new().unwrap();
    environment.set_odbc_version_3();
    let sources = environment.system_data_sources()
        .expect("Data sources can be iterated over");
    println!("{:?}", sources);

    let expected: [DataSourceInfo; 0] = [];
    assert!(sources.iter().eq(expected.iter()));
}

<|endoftext|>


<commit_before>#![cfg(feature = "encoding")]

extern crate lambda_calculus as lambda;

use lambda::*;
use lambda::data::list::*;

macro_rules! test_list {
    ($name:ident, $function:ident, $($($n:expr),+ => $result:expr),+) => (
        #[test]
        fn $name() {
            $(assert_eq!(beta(app!($function(), $($n.into_church()),*), HAP, 0), $result.into_church());)*
            $(assert_eq!(beta(app!($function(), $($n.into_scott()),*), HAP, 0), $result.into_scott());)*
            $(assert_eq!(beta(app!($function(), $($n.into_parigot()),*), HAP, 0), $result.into_parigot());)*
            $(assert_eq!(beta(app!($function(), $($n.into_stumpfu()),*), HAP, 0), $result.into_stumpfu());)*
        }
    );
}

macro_rules! test_list_enc {
    ($name:ident, $function:ident, $($($n:expr),+ => $result:expr),+) => (
        #[test]
        fn $name() {
            $(assert_eq!(beta(app!($function(Church),  $($n.into_church()),*), HAP, 0),  $result.into_church());)*
            $(assert_eq!(beta(app!($function(Scott),   $($n.into_scott()),*), HAP, 0),   $result.into_scott());)*
            $(assert_eq!(beta(app!($function(Parigot), $($n.into_parigot()),*), HAP, 0), $result.into_parigot());)*
            $(assert_eq!(beta(app!($function(StumpFu), $($n.into_stumpfu()),*), HAP, 0), $result.into_stumpfu());)*
        }
    );
}

test_list!(list_last, last,
    // TODO: test empty list?
    vec![1] => 1,
    vec![1, 2, 3] => 3
);

test_list_enc!(list_length, length,
    // TODO: test empty list
    vec![1] => 1,
    vec![1, 2] => 2,
    vec![1, 2, 3] => 3
);

test_list!(list_init, init,
    // TODO: test singleton list?
    vec![1, 2] => vec![1],
    vec![1, 2, 3] => vec![1, 2]
);

test_list!(list_zip, zip,
    // TODO: test empty list
    vec![1], vec![1] => vec![(1, 1)],
    vec![1, 2], vec![1] => vec![(1, 1)],
    vec![1], vec![1, 2] => vec![(1, 1)],
    vec![1, 2], vec![3, 4] => vec![(1, 3), (2, 4)]
);

/* TODO: figure out passing multiple functions (inconsistent lockstep iteration)
test_list!(list_zip, zip_with, add,
    // TODO: test empty list
    vec![1], vec![1] => vec![2],
    vec![1, 2], vec![1] => vec![2],
    vec![1], vec![1, 2] => vec![2],
    vec![1, 2], vec![3, 4] => vec![4, 6]
);
#[test]
fn list_take_while() {
    let l1 = || { vec![0, 0, 2, 3].into_scott() };
    let l2 = || { vec![0, 0].into_scott() };
    let l3 = || { vec![1, 4, 2, 3].into_scott() };
    let l4 = || { vec![0, 4, 0, 0].into_scott() };
    let l5 = || { vec![0].into_scott() };

    assert_eq!(beta(app!(take_while(), is_zero(), nil()), HAP, 0), nil());
    assert_eq!(beta(app!(take_while(), is_zero(), l1()), HAP, 0), l2());
    assert_eq!(beta(app!(take_while(), is_zero(), l2()), HAP, 0), l2());
    assert_eq!(beta(app!(take_while(), is_zero(), l3()), HAP, 0), nil());
    assert_eq!(beta(app!(take_while(), is_zero(), l4()), HAP, 0), l5());
}
*/
<commit_msg>work around empty list issue in list integration tests; test list::take<commit_after>#![cfg(feature = "encoding")]

extern crate lambda_calculus as lambda;

use lambda::*;
use lambda::data::list::*;

macro_rules! test_list {
    ($name:ident, $function:ident, $($($n:expr),+ => $result:expr),+) => (
        #[test]
        fn $name() {
            $(assert_eq!(beta(app!($function(), $($n.into_church()),*), HAP, 0), $result.into_church());)*
            $(assert_eq!(beta(app!($function(), $($n.into_scott()),*), HAP, 0), $result.into_scott());)*
            $(assert_eq!(beta(app!($function(), $($n.into_parigot()),*), HAP, 0), $result.into_parigot());)*
            $(assert_eq!(beta(app!($function(), $($n.into_stumpfu()),*), HAP, 0), $result.into_stumpfu());)*
        }
    );
}

macro_rules! test_list_enc {
    ($name:ident, $function:ident, $($($n:expr),+ => $result:expr),+) => (
        #[test]
        fn $name() {
            $(assert_eq!(beta(app!($function(Church),  $($n.into_church()),*), HAP, 0),  $result.into_church());)*
            $(assert_eq!(beta(app!($function(Scott),   $($n.into_scott()),*), HAP, 0),   $result.into_scott());)*
            $(assert_eq!(beta(app!($function(Parigot), $($n.into_parigot()),*), HAP, 0), $result.into_parigot());)*
            $(assert_eq!(beta(app!($function(StumpFu), $($n.into_stumpfu()),*), HAP, 0), $result.into_stumpfu());)*
        }
    );
}

fn empty() -> Vec<usize> { vec![] } // a workaround to pass vec![] to the testing macro

test_list!(list_last, last,
    vec![1] => 1,
    vec![1, 2, 3] => 3
);

test_list_enc!(list_length, length,
    empty() => 0,
    vec![1] => 1,
    vec![1, 2] => 2,
    vec![1, 2, 3] => 3
);

test_list!(list_init, init,
    vec![1] => empty(),
    vec![1, 2] => vec![1],
    vec![1, 2, 3] => vec![1, 2]
);

test_list!(list_zip, zip,
    empty(),
    vec![1], vec![1] => vec![(1, 1)],
    vec![1, 2], vec![1] => vec![(1, 1)],
    vec![1], vec![1, 2] => vec![(1, 1)],
    vec![1, 2], vec![3, 4] => vec![(1, 3), (2, 4)]
);

test_list_enc!(list_take, take,
    0, empty() => empty(),
    1, empty() => empty(),
    0, vec![1] => empty(),
    1, vec![1] => vec![1],
    2, vec![1] => vec![1],
    1, vec![1, 2] => vec![1],
    2, vec![1, 2] => vec![1, 2],
    3, vec![1, 2] => vec![1, 2]
);

/* TODO: figure out passing multiple functions (inconsistent lockstep iteration)
test_list!(list_zip, zip_with, add,
    // TODO: test empty list
    vec![1], vec![1] => vec![2],
    vec![1, 2], vec![1] => vec![2],
    vec![1], vec![1, 2] => vec![2],
    vec![1, 2], vec![3, 4] => vec![4, 6]
);
#[test]
fn list_take_while() {
    let l1 = || { vec![0, 0, 2, 3].into_scott() };
    let l2 = || { vec![0, 0].into_scott() };
    let l3 = || { vec![1, 4, 2, 3].into_scott() };
    let l4 = || { vec![0, 4, 0, 0].into_scott() };
    let l5 = || { vec![0].into_scott() };

    assert_eq!(beta(app!(take_while(), is_zero(), nil()), HAP, 0), nil());
    assert_eq!(beta(app!(take_while(), is_zero(), l1()), HAP, 0), l2());
    assert_eq!(beta(app!(take_while(), is_zero(), l2()), HAP, 0), l2());
    assert_eq!(beta(app!(take_while(), is_zero(), l3()), HAP, 0), nil());
    assert_eq!(beta(app!(take_while(), is_zero(), l4()), HAP, 0), l5());
}
*/
<|endoftext|>


<commit_before>use desync::scheduler::*;

use super::timeout::*;

use std::thread;
use std::time::*;
use std::sync::*;
use std::sync::mpsc::*;

use futures::prelude::*;
use futures::task;
use futures::task::{ArcWake, Poll};
use futures::channel::oneshot;

#[test]
fn schedule_future() {
    timeout(|| {
        use futures::executor;

        let queue       = queue();
        let future      = future_sync(&queue, move || async {
            thread::sleep(Duration::from_millis(100));
            42
        });

        executor::block_on(async {
            assert!(future.await.unwrap() == 42);
        });
    }, 500);
}

#[test]
fn schedule_future_with_no_scheduler_threads() {
    timeout(|| {
        use futures::executor;

        let scheduler   = Scheduler::new();

        // Even with 0 threads, futures should still run (by draining on the current thread as for sync actions)
        scheduler.set_max_threads(0);
        scheduler.despawn_threads_if_overloaded();

        let queue       = queue();
        let future      = scheduler.future_sync(&queue, move || async {
            thread::sleep(Duration::from_millis(100));
            42
        });

        executor::block_on(async {
            assert!(future.await.unwrap() == 42);
        });
    }, 500);
}

#[test]
fn wake_future_with_no_scheduler_threads() {
    timeout(|| {
        use futures::executor;

        let (tx, rx)    = oneshot::channel::<i32>();
        let scheduler   = Scheduler::new();

        // Even with 0 threads, futures should still run (by draining on the current thread as for sync actions)
        scheduler.set_max_threads(0);
        scheduler.despawn_threads_if_overloaded();

        // Schedule a future that will block until we send a value
        let queue       = queue();
        let future      = scheduler.future_sync(&queue, move || async {
            rx.await.expect("Receive result")
        });

        // Schedule a thread that will send a value
        thread::spawn(move || {
            // Wait for a bit before sending the result so the future should block
            thread::sleep(Duration::from_millis(100));

            tx.send(42).expect("Send")
        });

        executor::block_on(async {
            assert!(future.await.expect("result") == 42);
        });
    }, 500);
}

#[test]
fn wait_for_future() {
    timeout(|| {
        use futures::executor;

        // We use a oneshot as our future, and a mpsc channel to track progress
        let (tx, rx)                = channel();
        let (future_tx, future_rx)  = oneshot::channel();

        let scheduler   = scheduler();
        let queue       = queue();

        // Start by sending '1' from an async
        let tx2 = tx.clone();
        desync(&queue, move || { tx2.send(1).unwrap(); });

        // Then send the value sent via our oneshot using a future
        let tx2 = tx.clone();
        let future = scheduler.after(&queue, future_rx,
            move |val| val.map(move |val| { tx2.send(val).unwrap(); 4 }));

        // Then send '3'
        let tx2 = tx.clone();
        desync(&queue, move || { tx2.send(3).unwrap(); });

        // '1' should be available, but we should otherwise be blocked on the future
        assert!(rx.recv().unwrap() == 1);
        assert!(rx.recv_timeout(Duration::from_millis(100)).is_err());

        // Send '2' to the future
        future_tx.send(2).unwrap();

        executor::block_on(async {
            // Future should resolve to 4
            assert!(future.await.unwrap() == Ok(4));

            // Should receive the '2' from the future, then 3
            assert!(rx.recv_timeout(Duration::from_millis(100)).unwrap() == 2);
            assert!(rx.recv().unwrap() == 3);
        });
    }, 500);
}

#[test]
fn future_waits_for_us() {
    timeout(|| {
        use futures::executor;

        // We use a oneshot as our future, and a mpsc channel to track progress
        let (tx, rx)                = channel();
        let (future_tx, future_rx)  = oneshot::channel();

        let scheduler   = scheduler();
        let queue       = queue();

        // Start by sending '1' from an async
        let tx2 = tx.clone();
        desync(&queue, move || { thread::sleep(Duration::from_millis(100)); tx2.send(1).unwrap(); });

        // Then send the value sent via our oneshot using a future
        let tx2 = tx.clone();
        let future = scheduler.after(&queue, future_rx,
            move |val| val.map(move |val| { tx2.send(val).unwrap(); 4 }));

        // Then send '3'
        let tx2 = tx.clone();
        desync(&queue, move || { tx2.send(3).unwrap(); });

        // Send '2' to the future
        future_tx.send(2).unwrap();

        executor::block_on(async {
            // Future should resolve to 4
            assert!(future.await.unwrap() == Ok(4));

            // '1' should be available first
            assert!(rx.recv().unwrap() == 1);

            // Should receive the '2' from the future, then 3
            assert!(rx.recv_timeout(Duration::from_millis(100)).unwrap() == 2);
            assert!(rx.recv().unwrap() == 3);
        });
    }, 500);
}

///
/// Used for polling futures to see if they've notified us yet
///
struct TestWaker {
    pub awake: Mutex<bool>
}

impl ArcWake for TestWaker {
    fn wake_by_ref(arc_self: &Arc<Self>) {
        (*arc_self.awake.lock().unwrap()) = true;
    }
}

#[test]
fn wait_for_sync_future_from_desync_future() {
    use futures::executor;

    timeout(|| {
        // This reproduces a deadlock due to a race condition, so we usually need several iterations through the test before the issue will occur
        for _i in 0..1000 {
            // We'll schedule a sync future on queue1, and wait for it from a desync future on queue2
            let queue1      = queue();
            let queue2      = queue();

            // Oneshot channel to wake the sync queue
            let (done1, recv1)  = oneshot::channel::<()>();

            let sync_future     = future_sync(&queue1, move || { async move { recv1.await.ok(); } });
            let desync_future   = future_desync(&queue2, move || { async move { sync_future.await.ok(); } });

            // Signal
            done1.send(()).unwrap();

            // Wait for the desync future in an executor
            executor::block_on(async move {
                desync_future.await.ok();
            });

            // Run sync on both queues
            sync(&queue1, move || { });
            sync(&queue2, move || { });
        }
    }, 5000);
}

#[test]
fn wait_for_sync_future_from_desync_future_without_awaiting() {
    timeout(|| {
        // This reproduces a deadlock due to a race condition, so we usually need several iterations through the test before the issue will occur
        for _i in 0..1000 {
            // We'll schedule a sync future on queue1, and wait for it from a desync future on queue2
            let queue1      = queue();
            let queue2      = queue();

            // Oneshot channel to wake the sync queue
            let (done1, recv1)  = oneshot::channel::<()>();

            let sync_future     = future_sync(&queue1, move || { async move { recv1.await.ok(); } });
            let _desync_future  = future_desync(&queue2, move || { async move { sync_future.await.ok(); println!("Future complete"); } });

            // Signal
            done1.send(()).unwrap();

            // Run sync on both queues
            println!("Q1");
            sync(&queue1, move || { println!("  OK"); });
            println!("Q2");
            sync(&queue2, move || { println!("  OK"); });
            println!("Drop");
        }
    }, 500);
}

#[test]
fn wait_for_desync_future_from_sync_future() {
    use futures::executor;

    timeout(|| {
        // This reproduces a deadlock due to a race condition, so we usually need several iterations through the test before the issue will occur
        for _i in 0..1000 {
            // We'll schedule a sync future on queue1, and wait for it from a desync future on queue2
            let queue1      = queue();
            let queue2      = queue();

            // Oneshot channel to wake the sync queue
            let (done1, recv1)  = oneshot::channel::<()>();

            let desync_future   = future_desync(&queue1, move || { async move { recv1.await.ok(); } });
            let sync_future     = future_sync(&queue2, move || { async move { desync_future.await.ok(); } });

            // Signal
            done1.send(()).unwrap();

            // Wait for the desync future in an executor
            executor::block_on(async move {
                sync_future.await.ok();
            });

            // Run sync on both queues
            sync(&queue1, move || { });
            sync(&queue2, move || { });
        }
    }, 5000);
}

#[test]
fn wait_for_sync_future_from_sync_future() {
    use futures::executor;

    timeout(|| {
        // This reproduces a deadlock due to a race condition, so we usually need several iterations through the test before the issue will occur
        for _i in 0..1000 {
            // We'll schedule a sync future on queue1, and wait for it from a desync future on queue2
            let queue1      = queue();
            let queue2      = queue();

            // Oneshot channel to wake the sync queue
            let (done1, recv1)  = oneshot::channel::<()>();

            let nested_future   = future_sync(&queue1, move || { async move { recv1.await.ok(); } });
            let desync_future   = future_sync(&queue2, move || { async move { nested_future.await.ok(); } });

            // Signal
            done1.send(()).unwrap();

            // Wait for the desync future in an executor
            executor::block_on(async move {
                desync_future.await.ok();
            });

            // Run sync on both queues
            sync(&queue1, move || { });
            sync(&queue2, move || { });
        }
    }, 5000);
}

#[test]
fn poll_two_futures_on_one_queue() {
    // 0 threads so we force the future to act in 'drain' mode
    let scheduler   = Scheduler::new();

    // Even with 0 threads, futures should still run (by draining on the current thread as for sync actions)
    scheduler.set_max_threads(0);
    scheduler.despawn_threads_if_overloaded();

    // If a single queue has a future on
    let queue           = queue();
    let (done1, recv1)  = oneshot::channel::<()>();
    let (done2, recv2)  = oneshot::channel::<()>();

    let wake1           = Arc::new(TestWaker { awake: Mutex::new(false) });
    let wake2           = Arc::new(TestWaker { awake: Mutex::new(false) });

    // Wait for done1 then done2 to signal
    let mut future_1    = scheduler.future_sync(&queue, move || {
        async move { recv1.await.ok(); }
    });

    let mut future_2    = scheduler.future_sync(&queue, move || {
        async move { recv2.await.ok(); }
    });

    // Poll future 1 then future 2 (as there are no threads to run, we'll use the 'drain on current thread' style, which will return pending as recv is pending)
    let waker_ref           = task::waker_ref(&wake1);
    let mut ctxt            = task::Context::from_waker(&waker_ref);

    assert!(future_1.poll_unpin(&mut ctxt) == Poll::Pending);

    // Only future_1 should be 'pollable' at this point (ie, is in the WaitForPoll state from the previous call)
    let waker_ref           = task::waker_ref(&wake2);
    let mut ctxt            = task::Context::from_waker(&waker_ref);

    assert!(future_2.poll_unpin(&mut ctxt) == Poll::Pending);

    // Finish both futures
    done1.send(()).unwrap();

    let waker_ref           = task::waker_ref(&wake2);
    let mut ctxt            = task::Context::from_waker(&waker_ref);

    // Poll the other future: it should be pending as it's waiting to be scheduled
    assert!(future_2.poll_unpin(&mut ctxt) == Poll::Pending);

    done2.send(()).unwrap();

    // future_1 should be signalled for polling, future_2 should not (as it can't start until future_1 is finished)
    assert!((*wake2.awake.lock().unwrap()) == false);
    assert!((*wake1.awake.lock().unwrap()) == true);

    // Retrieve the result for future_1
    let waker_ref           = task::waker_ref(&wake1);
    let mut ctxt            = task::Context::from_waker(&waker_ref);

    assert!(future_1.poll_unpin(&mut ctxt) == Poll::Ready(Ok(())));

    // Both future 1 and future 2 should have signalled now

    // TODO: this is a possible bug with 0 threads - the thread won't reschedule after future_1 completes, so wake2 will not yet be set
    //          (This is quite a complicated problem: if the drain continued processing jobs until it became pending instead of scheduling
    //          in the background, this would work but the return from poll could be delayed indefinitely)
    // assert!((*wake2.awake.lock().unwrap()) == true);

    // Give the scheduler a chance to run the other future (it will be queued in the background, so this is required for the notification to occur)
    scheduler.set_max_threads(1);
    for _ in 0..100 {
        if *wake2.awake.lock().unwrap() { break; }
        thread::sleep(Duration::from_millis(1));
    }
    assert!((*wake2.awake.lock().unwrap()) == true);

    let waker_ref           = task::waker_ref(&wake2);
    let mut ctxt            = task::Context::from_waker(&waker_ref);

    // Should be able to retrieve the result of future_2
    assert!(future_2.poll_unpin(&mut ctxt) == Poll::Ready(Ok(())));

    // TODO: not actually sure if this is bad behaviour or not but if future_2 is polled first, future_1 won't be available until future_2
    //      completes. This is another 0 thread only issue as future_1 will be able to send its notification when the thread pool is available.
}
<commit_msg>Remove some debugging messages<commit_after>use desync::scheduler::*;

use super::timeout::*;

use std::thread;
use std::time::*;
use std::sync::*;
use std::sync::mpsc::*;

use futures::prelude::*;
use futures::task;
use futures::task::{ArcWake, Poll};
use futures::channel::oneshot;

#[test]
fn schedule_future() {
    timeout(|| {
        use futures::executor;

        let queue       = queue();
        let future      = future_sync(&queue, move || async {
            thread::sleep(Duration::from_millis(100));
            42
        });

        executor::block_on(async {
            assert!(future.await.unwrap() == 42);
        });
    }, 500);
}

#[test]
fn schedule_future_with_no_scheduler_threads() {
    timeout(|| {
        use futures::executor;

        let scheduler   = Scheduler::new();

        // Even with 0 threads, futures should still run (by draining on the current thread as for sync actions)
        scheduler.set_max_threads(0);
        scheduler.despawn_threads_if_overloaded();

        let queue       = queue();
        let future      = scheduler.future_sync(&queue, move || async {
            thread::sleep(Duration::from_millis(100));
            42
        });

        executor::block_on(async {
            assert!(future.await.unwrap() == 42);
        });
    }, 500);
}

#[test]
fn wake_future_with_no_scheduler_threads() {
    timeout(|| {
        use futures::executor;

        let (tx, rx)    = oneshot::channel::<i32>();
        let scheduler   = Scheduler::new();

        // Even with 0 threads, futures should still run (by draining on the current thread as for sync actions)
        scheduler.set_max_threads(0);
        scheduler.despawn_threads_if_overloaded();

        // Schedule a future that will block until we send a value
        let queue       = queue();
        let future      = scheduler.future_sync(&queue, move || async {
            rx.await.expect("Receive result")
        });

        // Schedule a thread that will send a value
        thread::spawn(move || {
            // Wait for a bit before sending the result so the future should block
            thread::sleep(Duration::from_millis(100));

            tx.send(42).expect("Send")
        });

        executor::block_on(async {
            assert!(future.await.expect("result") == 42);
        });
    }, 500);
}

#[test]
fn wait_for_future() {
    timeout(|| {
        use futures::executor;

        // We use a oneshot as our future, and a mpsc channel to track progress
        let (tx, rx)                = channel();
        let (future_tx, future_rx)  = oneshot::channel();

        let scheduler   = scheduler();
        let queue       = queue();

        // Start by sending '1' from an async
        let tx2 = tx.clone();
        desync(&queue, move || { tx2.send(1).unwrap(); });

        // Then send the value sent via our oneshot using a future
        let tx2 = tx.clone();
        let future = scheduler.after(&queue, future_rx,
            move |val| val.map(move |val| { tx2.send(val).unwrap(); 4 }));

        // Then send '3'
        let tx2 = tx.clone();
        desync(&queue, move || { tx2.send(3).unwrap(); });

        // '1' should be available, but we should otherwise be blocked on the future
        assert!(rx.recv().unwrap() == 1);
        assert!(rx.recv_timeout(Duration::from_millis(100)).is_err());

        // Send '2' to the future
        future_tx.send(2).unwrap();

        executor::block_on(async {
            // Future should resolve to 4
            assert!(future.await.unwrap() == Ok(4));

            // Should receive the '2' from the future, then 3
            assert!(rx.recv_timeout(Duration::from_millis(100)).unwrap() == 2);
            assert!(rx.recv().unwrap() == 3);
        });
    }, 500);
}

#[test]
fn future_waits_for_us() {
    timeout(|| {
        use futures::executor;

        // We use a oneshot as our future, and a mpsc channel to track progress
        let (tx, rx)                = channel();
        let (future_tx, future_rx)  = oneshot::channel();

        let scheduler   = scheduler();
        let queue       = queue();

        // Start by sending '1' from an async
        let tx2 = tx.clone();
        desync(&queue, move || { thread::sleep(Duration::from_millis(100)); tx2.send(1).unwrap(); });

        // Then send the value sent via our oneshot using a future
        let tx2 = tx.clone();
        let future = scheduler.after(&queue, future_rx,
            move |val| val.map(move |val| { tx2.send(val).unwrap(); 4 }));

        // Then send '3'
        let tx2 = tx.clone();
        desync(&queue, move || { tx2.send(3).unwrap(); });

        // Send '2' to the future
        future_tx.send(2).unwrap();

        executor::block_on(async {
            // Future should resolve to 4
            assert!(future.await.unwrap() == Ok(4));

            // '1' should be available first
            assert!(rx.recv().unwrap() == 1);

            // Should receive the '2' from the future, then 3
            assert!(rx.recv_timeout(Duration::from_millis(100)).unwrap() == 2);
            assert!(rx.recv().unwrap() == 3);
        });
    }, 500);
}

///
/// Used for polling futures to see if they've notified us yet
///
struct TestWaker {
    pub awake: Mutex<bool>
}

impl ArcWake for TestWaker {
    fn wake_by_ref(arc_self: &Arc<Self>) {
        (*arc_self.awake.lock().unwrap()) = true;
    }
}

#[test]
fn wait_for_sync_future_from_desync_future() {
    use futures::executor;

    timeout(|| {
        // This reproduces a deadlock due to a race condition, so we usually need several iterations through the test before the issue will occur
        for _i in 0..1000 {
            // We'll schedule a sync future on queue1, and wait for it from a desync future on queue2
            let queue1      = queue();
            let queue2      = queue();

            // Oneshot channel to wake the sync queue
            let (done1, recv1)  = oneshot::channel::<()>();

            let sync_future     = future_sync(&queue1, move || { async move { recv1.await.ok(); } });
            let desync_future   = future_desync(&queue2, move || { async move { sync_future.await.ok(); } });

            // Signal
            done1.send(()).unwrap();

            // Wait for the desync future in an executor
            executor::block_on(async move {
                desync_future.await.ok();
            });

            // Run sync on both queues
            sync(&queue1, move || { });
            sync(&queue2, move || { });
        }
    }, 5000);
}

#[test]
fn wait_for_sync_future_from_desync_future_without_awaiting() {
    timeout(|| {
        // This reproduces a deadlock due to a race condition, so we usually need several iterations through the test before the issue will occur
        for _i in 0..1000 {
            // We'll schedule a sync future on queue1, and wait for it from a desync future on queue2
            let queue1      = queue();
            let queue2      = queue();

            // Oneshot channel to wake the sync queue
            let (done1, recv1)  = oneshot::channel::<()>();

            let sync_future     = future_sync(&queue1, move || { async move { recv1.await.ok(); } });
            let _desync_future  = future_desync(&queue2, move || { async move { sync_future.await.ok(); } });

            // Signal
            done1.send(()).unwrap();

            // Run sync on both queues (these will schedule after the two futures have completed)
            sync(&queue1, move || { });
            sync(&queue2, move || { });
        }
    }, 500);
}

#[test]
fn wait_for_desync_future_from_sync_future() {
    use futures::executor;

    timeout(|| {
        // This reproduces a deadlock due to a race condition, so we usually need several iterations through the test before the issue will occur
        for _i in 0..1000 {
            // We'll schedule a sync future on queue1, and wait for it from a desync future on queue2
            let queue1      = queue();
            let queue2      = queue();

            // Oneshot channel to wake the sync queue
            let (done1, recv1)  = oneshot::channel::<()>();

            let desync_future   = future_desync(&queue1, move || { async move { recv1.await.ok(); } });
            let sync_future     = future_sync(&queue2, move || { async move { desync_future.await.ok(); } });

            // Signal
            done1.send(()).unwrap();

            // Wait for the desync future in an executor
            executor::block_on(async move {
                sync_future.await.ok();
            });

            // Run sync on both queues
            sync(&queue1, move || { });
            sync(&queue2, move || { });
        }
    }, 5000);
}

#[test]
fn wait_for_sync_future_from_sync_future() {
    use futures::executor;

    timeout(|| {
        // This reproduces a deadlock due to a race condition, so we usually need several iterations through the test before the issue will occur
        for _i in 0..1000 {
            // We'll schedule a sync future on queue1, and wait for it from a desync future on queue2
            let queue1      = queue();
            let queue2      = queue();

            // Oneshot channel to wake the sync queue
            let (done1, recv1)  = oneshot::channel::<()>();

            let nested_future   = future_sync(&queue1, move || { async move { recv1.await.ok(); } });
            let desync_future   = future_sync(&queue2, move || { async move { nested_future.await.ok(); } });

            // Signal
            done1.send(()).unwrap();

            // Wait for the desync future in an executor
            executor::block_on(async move {
                desync_future.await.ok();
            });

            // Run sync on both queues
            sync(&queue1, move || { });
            sync(&queue2, move || { });
        }
    }, 5000);
}

#[test]
fn poll_two_futures_on_one_queue() {
    // 0 threads so we force the future to act in 'drain' mode
    let scheduler   = Scheduler::new();

    // Even with 0 threads, futures should still run (by draining on the current thread as for sync actions)
    scheduler.set_max_threads(0);
    scheduler.despawn_threads_if_overloaded();

    // If a single queue has a future on
    let queue           = queue();
    let (done1, recv1)  = oneshot::channel::<()>();
    let (done2, recv2)  = oneshot::channel::<()>();

    let wake1           = Arc::new(TestWaker { awake: Mutex::new(false) });
    let wake2           = Arc::new(TestWaker { awake: Mutex::new(false) });

    // Wait for done1 then done2 to signal
    let mut future_1    = scheduler.future_sync(&queue, move || {
        async move { recv1.await.ok(); }
    });

    let mut future_2    = scheduler.future_sync(&queue, move || {
        async move { recv2.await.ok(); }
    });

    // Poll future 1 then future 2 (as there are no threads to run, we'll use the 'drain on current thread' style, which will return pending as recv is pending)
    let waker_ref           = task::waker_ref(&wake1);
    let mut ctxt            = task::Context::from_waker(&waker_ref);

    assert!(future_1.poll_unpin(&mut ctxt) == Poll::Pending);

    // Only future_1 should be 'pollable' at this point (ie, is in the WaitForPoll state from the previous call)
    let waker_ref           = task::waker_ref(&wake2);
    let mut ctxt            = task::Context::from_waker(&waker_ref);

    assert!(future_2.poll_unpin(&mut ctxt) == Poll::Pending);

    // Finish both futures
    done1.send(()).unwrap();

    let waker_ref           = task::waker_ref(&wake2);
    let mut ctxt            = task::Context::from_waker(&waker_ref);

    // Poll the other future: it should be pending as it's waiting to be scheduled
    assert!(future_2.poll_unpin(&mut ctxt) == Poll::Pending);

    done2.send(()).unwrap();

    // future_1 should be signalled for polling, future_2 should not (as it can't start until future_1 is finished)
    assert!((*wake2.awake.lock().unwrap()) == false);
    assert!((*wake1.awake.lock().unwrap()) == true);

    // Retrieve the result for future_1
    let waker_ref           = task::waker_ref(&wake1);
    let mut ctxt            = task::Context::from_waker(&waker_ref);

    assert!(future_1.poll_unpin(&mut ctxt) == Poll::Ready(Ok(())));

    // Both future 1 and future 2 should have signalled now

    // TODO: this is a possible bug with 0 threads - the thread won't reschedule after future_1 completes, so wake2 will not yet be set
    //          (This is quite a complicated problem: if the drain continued processing jobs until it became pending instead of scheduling
    //          in the background, this would work but the return from poll could be delayed indefinitely)
    // assert!((*wake2.awake.lock().unwrap()) == true);

    // Give the scheduler a chance to run the other future (it will be queued in the background, so this is required for the notification to occur)
    scheduler.set_max_threads(1);
    for _ in 0..100 {
        if *wake2.awake.lock().unwrap() { break; }
        thread::sleep(Duration::from_millis(1));
    }
    assert!((*wake2.awake.lock().unwrap()) == true);

    let waker_ref           = task::waker_ref(&wake2);
    let mut ctxt            = task::Context::from_waker(&waker_ref);

    // Should be able to retrieve the result of future_2
    assert!(future_2.poll_unpin(&mut ctxt) == Poll::Ready(Ok(())));

    // TODO: not actually sure if this is bad behaviour or not but if future_2 is polled first, future_1 won't be available until future_2
    //      completes. This is another 0 thread only issue as future_1 will be able to send its notification when the thread pool is available.
}
<|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 {
            wast::WastDirective::AssertMalformed {
                span,
                module: wast::QuoteModule::Module(module),
                message,
            } => (span, module, Err(message)),
            wast::WastDirective::Module(module) => (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>Include more spec tests<commit_after>#[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()
}
<|endoftext|>