<commit_before>#![crate_type = "bin"]

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

use gtk::{Orientation, SortType, Widget};
use gtk::prelude::*;

use sysinfo::*;

use std::cell::RefCell;
use std::collections::HashMap;
use std::rc::Rc;
use std::sync::{Arc, Mutex};

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

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

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

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

        let index = self.notebook.append_page(widget, Some(&tab));

        self.tabs.push(tab);

        Some(index)
    }
}

#[allow(dead_code)]
struct Procs {
    left_tree: gtk::TreeView,
    scroll: gtk::ScrolledWindow,
    current_pid: Rc<RefCell<Option<i64>>>,
    kill_button: Rc<RefCell<gtk::Button>>,
    vertical_layout: gtk::Box,
    list_store: gtk::ListStore,
}

unsafe impl Send for Procs {}

impl Procs {
    pub fn new<'a>(proc_list: &HashMap<usize, Process>, note: &mut NoteBook) -> Procs {
        let left_tree = gtk::TreeView::new();
        let scroll = gtk::ScrolledWindow::new(None, None);
        let current_pid = Rc::new(RefCell::new(None));
        let kill_button = Rc::new(RefCell::new(gtk::Button::new_with_label("End task")));
        let current_pid1 = current_pid.clone();
        let current_pid2 = current_pid.clone();
        let 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 (in kB)", &mut columns);

        for i in columns.iter() {
            left_tree.append_column(&i);
            i.connect_clicked(|model| {
                //let model = model.downcast::<gtk::TreeSortable>().unwrap();
                model.set_sort_column_id(0);
            });
        }

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

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

        left_tree.connect_cursor_changed(move |tree_view| {
            match tree_view.get_selection() {
                Some(selection) => {
                    if let Some((model, iter)) = selection.get_selected() {
                        let pid = Some(model.get_value(&iter, 0).get().unwrap());
                        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()));
        let vertical_layout : Widget = vertical_layout.upcast();

        note.create_tab("Process list", &vertical_layout);
        Procs {
            left_tree: left_tree,
            scroll: scroll,
            current_pid: current_pid2.clone(),
            kill_button: kill_button,
            vertical_layout: vertical_layout.downcast::<gtk::Box>().unwrap(),
            list_store: list_store,
        }
    }
}

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

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

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

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

    let val1 = pid.to_value();
    let val2 = memory.to_value();
    let top_level = list_store.append();
    list_store.set_value(&top_level, 0, &val1);
    list_store.set_value(&top_level, 1, &name.to_value());
    list_store.set_value(&top_level, 2, &format!("{:.1}", cpu).to_value());
    list_store.set_value(&top_level, 3, &val2);
}

fn update_window(list: &mut gtk::ListStore, system: Arc<Mutex<sysinfo::System>>,
                 info: Arc<Mutex<DisplaySysInfo>>) {
    let system = &mut system.lock().unwrap();
    let info = &mut info.lock().unwrap();

    system.refresh_all();
    let mut entries : HashMap<usize, Process> = system.get_process_list().clone();
    let mut nb = list.iter_n_children(None);

    info.update_ram_display(&system);
    info.update_process_display(&system);

    let mut i = 0;
    while i < nb {
        if let Some(mut iter) = list.iter_nth_child(None, i) {
            let pid : Option<i64> = list.get_value(&iter, 0).get();
            if pid.is_none() {
                i += 1;
                continue;
            }
            let pid = pid.unwrap();
            let mut to_delete = false;

            match entries.get(&(pid as usize)) {
                Some(p) => {
                    let val2 = p.memory.to_value();
                    list.set_value(&iter, 2, &format!("{:.1}", p.cpu_usage).to_value());
                    list.set_value(&iter, 3, &val2);
                    to_delete = true;
                }
                None => {
                    list.remove(&mut iter);
                }
            }
            if to_delete {
                entries.remove(&(pid as usize));
                nb = list.iter_n_children(None);
                i += 1;
            }
        } else {
            i += 1;
        }
    }
    for (_, pro) in entries {
        create_and_fill_model(list, pro.pid, &pro.cmd, &pro.name, pro.cpu_usage, pro.memory);
    }
}

#[allow(dead_code)]
struct DisplaySysInfo {
    procs : Rc<RefCell<Vec<gtk::ProgressBar>>>,
    ram : Rc<RefCell<gtk::ProgressBar>>,
    swap : Rc<RefCell<gtk::ProgressBar>>,
    vertical_layout : Rc<RefCell<gtk::Box>>,
}

impl DisplaySysInfo {
    pub fn new(sys1: Arc<Mutex<sysinfo::System>>, note: &mut NoteBook) -> DisplaySysInfo {
        let sys2 = sys1.clone();

        let vertical_layout = gtk::Box::new(gtk::Orientation::Vertical, 0);
        let mut procs = Vec::new();
        let ram = gtk::ProgressBar::new();
        let swap = gtk::ProgressBar::new();

        ram.set_show_text(true);
        swap.set_show_text(true);
        vertical_layout.set_spacing(5);

        let mut i = 0;
        let mut total = false;

        vertical_layout.pack_start(&gtk::Label::new(Some("Memory usage")), false, false, 15);
        vertical_layout.add(&ram);
        vertical_layout.pack_start(&gtk::Label::new(Some("Swap usage")), false, false, 15);
        vertical_layout.add(&swap);
        vertical_layout.pack_start(&gtk::Label::new(Some("Total CPU usage")), false, false, 15);
        for pro in sys1.lock().unwrap().get_processor_list() {
            if total {
                procs.push(gtk::ProgressBar::new());
                let p : &gtk::ProgressBar = &procs[i];
                let l = gtk::Label::new(Some(&format!("{}", i)));
                let horizontal_layout = gtk::Box::new(gtk::Orientation::Horizontal, 0);

                p.set_text(Some(&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);
            } else {
                procs.push(gtk::ProgressBar::new());
                let p : &gtk::ProgressBar = &procs[i];

                p.set_text(Some(&format!("{:.2} %", pro.get_cpu_usage() * 100.)));
                p.set_show_text(true);
                p.set_fraction(pro.get_cpu_usage() as f64);

                vertical_layout.add(p);
                vertical_layout.pack_start(&gtk::Label::new(Some("Process usage")), false,
                                           false, 15);
                total = true;
            }
            i += 1;
        }

        let vertical_layout : Widget = vertical_layout.upcast();
        note.create_tab("System usage", &vertical_layout);
        let vertical_layout : gtk::Box = vertical_layout.downcast::<gtk::Box>().unwrap();

        let mut tmp = DisplaySysInfo {
            procs: Rc::new(RefCell::new(procs)),
            ram: Rc::new(RefCell::new(ram)),
            swap: Rc::new(RefCell::new(swap)),
            vertical_layout: Rc::new(RefCell::new(vertical_layout)),
        };
        tmp.update_ram_display(&sys2.lock().unwrap());
        tmp
    }

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

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

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

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

    pub fn update_process_display(&mut self, sys: &sysinfo::System) {
        let v = &*self.procs.borrow_mut();
        let mut i = 0;

        for pro in sys.get_processor_list() {
            v[i].set_text(Some(&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;
        }
    }
}

fn main() {
    gtk::init().expect("GTK couldn't start normally");

    let window = gtk::Window::new(gtk::WindowType::Toplevel);
    let sys : Arc<Mutex<sysinfo::System>> = Arc::new(Mutex::new(sysinfo::System::new()));
    let mut note = NoteBook::new();
    let mut procs = Procs::new(sys.lock().unwrap().get_process_list(), &mut note);
    let current_pid2 = procs.current_pid.clone();
    let sys1 = sys.clone();
    let sys2 = sys.clone();

    window.set_title("Process viewer");
    window.set_position(gtk::WindowPosition::Center);

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

    { sys.lock().unwrap().refresh_all(); }
    (*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.lock().unwrap().get_process(s.unwrap()) {
                Some(p) => {
                    p.kill(Signal::Kill);
                },
                None => {}
            };
        }
    });

    let display_tab = DisplaySysInfo::new(sys2, &mut note);
    let m_display_tab = Arc::new(Mutex::new(display_tab));

    gtk::timeout_add(1500, move || {
        update_window(&mut procs.list_store, sys1.clone(), m_display_tab.clone());
        glib::Continue(true)
    });

    window.add(&note.notebook);
    window.show_all();
    gtk::main();
}
<commit_msg>Little improvement<commit_after>#![crate_type = "bin"]

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

use gtk::{Orientation, SortColumn, SortType, TreeModel, TreeSortable, Widget};
use gtk::prelude::*;

use sysinfo::*;

use std::cell::RefCell;
use std::collections::HashMap;
use std::rc::Rc;
use std::sync::{Arc, Mutex};

macro_rules! set_sort {
    ($id:expr, $columns:expr) => {
        $columns.get($id).unwrap().connect_clicked(|model| {
            model.set_sort_column_id($id);
        });
    }
}

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

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

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

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

        let index = self.notebook.append_page(widget, Some(&tab));

        self.tabs.push(tab);

        Some(index)
    }
}

#[allow(dead_code)]
struct Procs {
    left_tree: gtk::TreeView,
    scroll: gtk::ScrolledWindow,
    current_pid: Rc<RefCell<Option<i64>>>,
    kill_button: Rc<RefCell<gtk::Button>>,
    vertical_layout: gtk::Box,
    list_store: gtk::ListStore,
}

unsafe impl Send for Procs {}

impl Procs {
    pub fn new<'a>(proc_list: &HashMap<usize, Process>, note: &mut NoteBook) -> Procs {
        let left_tree = gtk::TreeView::new();
        let scroll = gtk::ScrolledWindow::new(None, None);
        let current_pid = Rc::new(RefCell::new(None));
        let kill_button = Rc::new(RefCell::new(gtk::Button::new_with_label("End task")));
        let current_pid1 = current_pid.clone();
        let current_pid2 = current_pid.clone();
        let 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, &left_tree);
        set_sort!(0, columns);
        append_column("process name", &mut columns, &left_tree);
        set_sort!(1, columns);
        append_column("cpu usage", &mut columns, &left_tree);
        set_sort!(2, columns);
        append_column("memory usage (in kB)", &mut columns, &left_tree);
        set_sort!(3, columns);

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

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

        left_tree.connect_cursor_changed(move |tree_view| {
            match tree_view.get_selection() {
                Some(selection) => {
                    if let Some((model, iter)) = selection.get_selected() {
                        let pid = Some(model.get_value(&iter, 0).get().unwrap());
                        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()));
        let vertical_layout : Widget = vertical_layout.upcast();

        note.create_tab("Process list", &vertical_layout);
        Procs {
            left_tree: left_tree,
            scroll: scroll,
            current_pid: current_pid2.clone(),
            kill_button: kill_button,
            vertical_layout: vertical_layout.downcast::<gtk::Box>().unwrap(),
            list_store: list_store,
        }
    }
}

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

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

    tmp.set_title(title);
    tmp.set_resizable(true);
    tmp.pack_start(&renderer, true);
    tmp.add_attribute(&renderer, "text", l as i32);
    tmp.set_clickable(true);
    left_tree.append_column(&tmp);
    /*if len < 1 {
        left_tree.get_model().unwrap()
                 .downcast::<TreeSortable>().unwrap()
                 .set_sort_func(SortColumn::Index(0), |m, it1, it2| {
                     let it1 : String = m.upcast::<TreeModel>().get_value(it1, 0).get().unwrap();
                     let it2 : String = m.upcast::<TreeModel>().get_value(it2, 0).get().unwrap();
                     it1.cmp(&it2)
                 });
    }*/
}

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

    let val1 = pid.to_value();
    let val2 = memory.to_value();
    let top_level = list_store.append();
    list_store.set_value(&top_level, 0, &val1);
    list_store.set_value(&top_level, 1, &name.to_value());
    list_store.set_value(&top_level, 2, &format!("{:.1}", cpu).to_value());
    list_store.set_value(&top_level, 3, &val2);
}

fn update_window(list: &mut gtk::ListStore, system: Arc<Mutex<sysinfo::System>>,
                 info: Arc<Mutex<DisplaySysInfo>>) {
    let system = &mut system.lock().unwrap();
    let info = &mut info.lock().unwrap();

    system.refresh_all();
    let mut entries : HashMap<usize, Process> = system.get_process_list().clone();
    let mut nb = list.iter_n_children(None);

    info.update_ram_display(&system);
    info.update_process_display(&system);

    let mut i = 0;
    while i < nb {
        if let Some(mut iter) = list.iter_nth_child(None, i) {
            let pid : Option<i64> = list.get_value(&iter, 0).get();
            if pid.is_none() {
                i += 1;
                continue;
            }
            let pid = pid.unwrap();
            let mut to_delete = false;

            match entries.get(&(pid as usize)) {
                Some(p) => {
                    let val2 = p.memory.to_value();
                    list.set_value(&iter, 2, &format!("{:.1}", p.cpu_usage).to_value());
                    list.set_value(&iter, 3, &val2);
                    to_delete = true;
                }
                None => {
                    list.remove(&mut iter);
                }
            }
            if to_delete {
                entries.remove(&(pid as usize));
                nb = list.iter_n_children(None);
                i += 1;
            }
        } else {
            i += 1;
        }
    }
    for (_, pro) in entries {
        create_and_fill_model(list, pro.pid, &pro.cmd, &pro.name, pro.cpu_usage, pro.memory);
    }
}

#[allow(dead_code)]
struct DisplaySysInfo {
    procs : Rc<RefCell<Vec<gtk::ProgressBar>>>,
    ram : Rc<RefCell<gtk::ProgressBar>>,
    swap : Rc<RefCell<gtk::ProgressBar>>,
    vertical_layout : Rc<RefCell<gtk::Box>>,
}

impl DisplaySysInfo {
    pub fn new(sys1: Arc<Mutex<sysinfo::System>>, note: &mut NoteBook) -> DisplaySysInfo {
        let sys2 = sys1.clone();

        let vertical_layout = gtk::Box::new(gtk::Orientation::Vertical, 0);
        let mut procs = Vec::new();
        let ram = gtk::ProgressBar::new();
        let swap = gtk::ProgressBar::new();

        ram.set_show_text(true);
        swap.set_show_text(true);
        vertical_layout.set_spacing(5);

        let mut i = 0;
        let mut total = false;

        vertical_layout.pack_start(&gtk::Label::new(Some("Memory usage")), false, false, 15);
        vertical_layout.add(&ram);
        vertical_layout.pack_start(&gtk::Label::new(Some("Swap usage")), false, false, 15);
        vertical_layout.add(&swap);
        vertical_layout.pack_start(&gtk::Label::new(Some("Total CPU usage")), false, false, 15);
        for pro in sys1.lock().unwrap().get_processor_list() {
            if total {
                procs.push(gtk::ProgressBar::new());
                let p : &gtk::ProgressBar = &procs[i];
                let l = gtk::Label::new(Some(&format!("{}", i)));
                let horizontal_layout = gtk::Box::new(gtk::Orientation::Horizontal, 0);

                p.set_text(Some(&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);
            } else {
                procs.push(gtk::ProgressBar::new());
                let p : &gtk::ProgressBar = &procs[i];

                p.set_text(Some(&format!("{:.2} %", pro.get_cpu_usage() * 100.)));
                p.set_show_text(true);
                p.set_fraction(pro.get_cpu_usage() as f64);

                vertical_layout.add(p);
                vertical_layout.pack_start(&gtk::Label::new(Some("Process usage")), false,
                                           false, 15);
                total = true;
            }
            i += 1;
        }

        let vertical_layout : Widget = vertical_layout.upcast();
        note.create_tab("System usage", &vertical_layout);
        let vertical_layout : gtk::Box = vertical_layout.downcast::<gtk::Box>().unwrap();

        let mut tmp = DisplaySysInfo {
            procs: Rc::new(RefCell::new(procs)),
            ram: Rc::new(RefCell::new(ram)),
            swap: Rc::new(RefCell::new(swap)),
            vertical_layout: Rc::new(RefCell::new(vertical_layout)),
        };
        tmp.update_ram_display(&sys2.lock().unwrap());
        tmp
    }

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

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

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

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

    pub fn update_process_display(&mut self, sys: &sysinfo::System) {
        let v = &*self.procs.borrow_mut();
        let mut i = 0;

        for pro in sys.get_processor_list() {
            v[i].set_text(Some(&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;
        }
    }
}

fn main() {
    gtk::init().expect("GTK couldn't start normally");

    let window = gtk::Window::new(gtk::WindowType::Toplevel);
    let sys : Arc<Mutex<sysinfo::System>> = Arc::new(Mutex::new(sysinfo::System::new()));
    let mut note = NoteBook::new();
    let mut procs = Procs::new(sys.lock().unwrap().get_process_list(), &mut note);
    let current_pid2 = procs.current_pid.clone();
    let sys1 = sys.clone();
    let sys2 = sys.clone();

    window.set_title("Process viewer");
    window.set_position(gtk::WindowPosition::Center);

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

    { sys.lock().unwrap().refresh_all(); }
    (*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.lock().unwrap().get_process(s.unwrap()) {
                Some(p) => {
                    p.kill(Signal::Kill);
                },
                None => {}
            };
        }
    });

    let display_tab = DisplaySysInfo::new(sys2, &mut note);
    let m_display_tab = Arc::new(Mutex::new(display_tab));

    gtk::timeout_add(1500, move || {
        update_window(&mut procs.list_store, sys1.clone(), m_display_tab.clone());
        glib::Continue(true)
    });

    window.add(&note.notebook);
    window.show_all();
    gtk::main();
}
<|endoftext|>


<commit_before>use std::env;
use std::io::Write;
use std::process::{Command, Stdio};
use std::path::Path;

pub struct Git {
    pub host: String,
    pub token: String,
}

impl Git {
    pub fn new(host: &str, token: &str) -> Git {
        Git {
            host: host.to_string(),
            token: token.to_string(),
        }
    }

    pub fn run(&self, args: &[&str], cwd: &Path) -> Result<String, String> {
        self.do_run(args, cwd, None)
    }

    pub fn run_with_stdin(&self, args: &[&str], cwd: &Path, stdin: &str) -> Result<String, String> {
        self.do_run(args, cwd, Some(stdin))
    }

    fn ask_pass_path(&self) -> String {
        let ask_pass = "octobot-ask-pass";
        match env::current_exe() {
            Ok(ref exe) if exe.parent().is_some() => {
                exe.parent().unwrap().join(ask_pass).to_string_lossy().into_owned()
            }
            _ => ask_pass.to_string(),
        }

    }

    pub fn has_branch(&self, branch: &str, cwd: &Path) -> Result<bool, String> {
        let output = try!(self.run(&["branch"], cwd));
        // skip first two characters for the bullet point
        let branches: Vec<String> = output.split("\n").filter(|b| b.len() > 2).map(|b| b[2..].to_string()).collect();
        Ok(branches.contains(&branch.to_string()))
    }

    fn do_run(&self, args: &[&str], cwd: &Path, stdin: Option<&str>) -> Result<String, String> {
        debug!("Running git with args: {:?}", args);
        let cmd = Command::new("git")
            .current_dir(cwd)
            .stdin(if stdin.is_some() {
                Stdio::piped()
            } else {
                Stdio::null()
            })
            .stderr(Stdio::piped())
            .stdout(Stdio::piped())
            .args(args)
            .env("GIT_ASKPASS", &self.ask_pass_path())
            .env("OCTOBOT_HOST", &self.host)
            .env("OCTOBOT_PASS", &self.token)
            .spawn();

        let mut child = match cmd {
            Ok(c) => c,
            Err(e) => return Err(format!("Error starting git: {}", e)),
        };

        if let Some(ref stdin) = stdin {
            if let Some(ref mut child_stdin) = child.stdin {
                if let Err(e) = child_stdin.write_all(stdin.as_bytes()) {
                    return Err(format!("Error writing to stdin: {}", e));
                }
            }
        }

        let result = match child.wait_with_output() {
            Ok(r) => r,
            Err(e) => return Err(format!("Error running git: {}", e)),
        };

        let mut output = String::new();
        if result.stdout.len() > 0 {
            output += format!("{}", String::from_utf8_lossy(&result.stdout)).as_str();
        }

        if !result.status.success() {
            if result.stderr.len() > 0 {
                output += format!("{}", String::from_utf8_lossy(&result.stderr)).as_str();
            }
            Err(format!("Error running git (exit code {}):\n{}",
                        result.status.code().unwrap_or(-1),
                        output))
        } else {

            Ok(output)
        }
    }
}
<commit_msg>Trim git output<commit_after>use std::env;
use std::io::Write;
use std::process::{Command, Stdio};
use std::path::Path;

pub struct Git {
    pub host: String,
    pub token: String,
}

impl Git {
    pub fn new(host: &str, token: &str) -> Git {
        Git {
            host: host.to_string(),
            token: token.to_string(),
        }
    }

    pub fn run(&self, args: &[&str], cwd: &Path) -> Result<String, String> {
        self.do_run(args, cwd, None)
    }

    pub fn run_with_stdin(&self, args: &[&str], cwd: &Path, stdin: &str) -> Result<String, String> {
        self.do_run(args, cwd, Some(stdin))
    }

    fn ask_pass_path(&self) -> String {
        let ask_pass = "octobot-ask-pass";
        match env::current_exe() {
            Ok(ref exe) if exe.parent().is_some() => {
                exe.parent().unwrap().join(ask_pass).to_string_lossy().into_owned()
            }
            _ => ask_pass.to_string(),
        }

    }

    pub fn has_branch(&self, branch: &str, cwd: &Path) -> Result<bool, String> {
        let output = try!(self.run(&["branch"], cwd));
        // skip first two characters for the bullet point
        let branches: Vec<String> = output.split("\n").filter(|b| b.len() > 2).map(|b| b[2..].to_string()).collect();
        Ok(branches.contains(&branch.to_string()))
    }

    fn do_run(&self, args: &[&str], cwd: &Path, stdin: Option<&str>) -> Result<String, String> {
        debug!("Running git with args: {:?}", args);
        let cmd = Command::new("git")
            .current_dir(cwd)
            .stdin(if stdin.is_some() {
                Stdio::piped()
            } else {
                Stdio::null()
            })
            .stderr(Stdio::piped())
            .stdout(Stdio::piped())
            .args(args)
            .env("GIT_ASKPASS", &self.ask_pass_path())
            .env("OCTOBOT_HOST", &self.host)
            .env("OCTOBOT_PASS", &self.token)
            .spawn();

        let mut child = match cmd {
            Ok(c) => c,
            Err(e) => return Err(format!("Error starting git: {}", e)),
        };

        if let Some(ref stdin) = stdin {
            if let Some(ref mut child_stdin) = child.stdin {
                if let Err(e) = child_stdin.write_all(stdin.as_bytes()) {
                    return Err(format!("Error writing to stdin: {}", e));
                }
            }
        }

        let result = match child.wait_with_output() {
            Ok(r) => r,
            Err(e) => return Err(format!("Error running git: {}", e)),
        };

        let mut output = String::new();
        if result.stdout.len() > 0 {
            output += format!("{}", String::from_utf8_lossy(&result.stdout)).as_str();
        }

        if !result.status.success() {
            if result.stderr.len() > 0 {
                output += format!("{}", String::from_utf8_lossy(&result.stderr)).as_str();
            }
            Err(format!("Error running git (exit code {}):\n{}",
                        result.status.code().unwrap_or(-1),
                        output))
        } else {

            Ok(output.trim().to_string())
        }
    }
}
<|endoftext|>


<commit_before>//============================================================================
//
// A simple Mandelbrot image generator in Rust
//
// Glutin/Glium GUI Front-end
//
// Copyright (c) 2014 Gavin Baker <gavinb@antonym.org>
// Published under the MIT license
//
//============================================================================

#![allow(unused_must_use)]

use std::sync::mpsc::{channel, Sender, Receiver};
use std::vec::Vec;
use std::thread;
use std::io::Cursor;

use glium;
use glium::{Display, Surface};
use glium::glutin::{Event,VirtualKeyCode,ElementState};
use glium::backend::glutin_backend::GlutinFacade;
use image;

use engine::MandelEngine;
use protocol::{RenderType, EngineCommand, EngineStatus, PREVIEW_WIDTH, PREVIEW_HEIGHT};
use shaders;

//----------------------------------------------------------------------------

pub struct WindowController<'a> {
    window: &'a mut GlutinFacade,
    buffer_width: u32,
    buffer_height: u32,
    chan_wc_to_engine: Option<Sender<EngineCommand>>,
    chan_wc_from_engine: Option<Receiver<EngineStatus>>,
    chan_engine_to_wc: Option<Sender<EngineStatus>>,
    chan_engine_from_wc: Option<Receiver<EngineCommand>>,
    image: Option<Vec<u8>>,
    shader_program: glium::Program,
    texture: glium::Texture2d,
}

impl<'a> WindowController<'a> {
    pub fn new(window: &'a mut GlutinFacade) -> WindowController<'a> {

        // WindowController === Engine
        // (Sender<T>, Receiver<T>)
        // x_to_y == sender
        // x_from_y == receiver
        let (chan_wc_to_engine, chan_engine_from_wc) = channel();
        let (chan_engine_to_wc, chan_wc_from_engine) = channel();

        // Load sample image into teture for render test
        let image = image::load(Cursor::new(&include_bytes!("image.png")[..]),
                                image::PNG).unwrap().to_rgba();
        let image_dimensions = image.dimensions();
        let image = glium::texture::RawImage2d::from_raw_rgba_reversed(image.into_raw(), image_dimensions);
        let texture = glium::texture::Texture2d::new(window, image).unwrap();

        // Build shaders
        let program = glium::Program::from_source(window,
                                                  shaders::VERTEX_SHADER_SOURCE,
                                                  shaders::FRAGMENT_SHADER_SOURCE,
                                                  None).unwrap();

        let mut wc = WindowController { window: window,
                                        buffer_width: 0,
                                        buffer_height: 0,
                                        chan_wc_to_engine: Some(chan_wc_to_engine),
                                        chan_wc_from_engine: Some(chan_wc_from_engine),
                                        chan_engine_to_wc: Some(chan_engine_to_wc),
                                        chan_engine_from_wc: Some(chan_engine_from_wc),
                                       image: None,
                                        shader_program: program,
                                        texture: texture,
        };

        let (w, h) =  wc.window.get_framebuffer_dimensions();
        wc.buffer_width = w as u32;
        wc.buffer_height = h as u32;

//        let mut imgbuf = image::ImageBuffer::new(w, h);

        // x,y pos | u,v tex
        // wc.vertices = vec!(
        //     -1.0, -1.0, 0.0, 0.0,
        //      1.0, -1.0, 1.0, 0.0,
        //     -1.0,  1.0, 0.0, 1.0,
        //      1.0,  1.0, 1.0, 1.0,
        //     );

        //

        wc
    }

    pub fn run(&mut self) {

        self.start_engine();

        loop {
            while let Some(ev) = self.window.poll_events().next() {
                self.handle_window_event(ev);
            }
            self.maybe_update_display();
            self.draw();
        }
    }

    pub fn draw(&mut self) {

        let uniforms = uniform! {
            matrix: [
                [1.0, 0.0, 0.0, 0.0],
                [0.0, 1.0, 0.0, 0.0],
                [0.0, 0.0, 1.0, 0.0],
                [0.0, 0.0, 0.0, 1.0],
            ],
            tex: &self.texture,
        };

        #[derive(Copy, Clone)]
        struct Vertex {
            position: [f32; 2],
            texcoord: [f32; 2],
        }

        implement_vertex!(Vertex, position, texcoord);

        let vertex1 = Vertex { position: [-0.5, -0.5], texcoord: [1.0, 1.0] };
        let vertex2 = Vertex { position: [ 0.0,  0.5], texcoord: [0.0, 1.0] };
        let vertex3 = Vertex { position: [ 0.5, -0.25],texcoord: [1.0, 0.0] };
        let shape = vec![vertex1, vertex2, vertex3];

        let vertex_buffer = glium::VertexBuffer::new(self.window, &shape).unwrap();
        let indices = glium::index::NoIndices(glium::index::PrimitiveType::TrianglesList);

        let mut target = self.window.draw();
        target.clear_color(0.0, 0.0, 1.0, 1.0);
        target.draw(&vertex_buffer, &indices, &self.shader_program, &uniforms,
                  &Default::default()).unwrap();
        target.finish().unwrap();
    }

    pub fn start_engine(&mut self) {

        let engine_progress_ch = self.chan_engine_to_wc.take().expect("no engine_to_wc chan");
        let engine_cmd_ch = self.chan_engine_from_wc.take().expect("no engine_from_wc chan");

        let (w,h) = (self.buffer_width, self.buffer_height);

        thread::spawn(move || {

            let mut engine = MandelEngine::new(w, h);
            engine.serve(&engine_cmd_ch, &engine_progress_ch);
        });

        let cmd_ch = self.chan_wc_to_engine.as_ref().expect("no chan_wc_to_engine");

        cmd_ch.send(EngineCommand::Render(RenderType::PreviewRender));
        cmd_ch.send(EngineCommand::Render(RenderType::FullRender));
    }

    pub fn maybe_update_display(&mut self) {
        match self.chan_wc_from_engine {
            Some(ref ch) => {
                let status_msg = ch.try_recv();
                match status_msg {
                    Ok(status) =>
                        match status {
                            EngineStatus::Startup => println!("Startup..."),
                            EngineStatus::Processing(progress) => println!("Processing {}", progress),
                            EngineStatus::RenderComplete(typ, img) => {
                                println!("Render Complete!");
                                //self.image = Some(img);
                                let imgbuf = img.as_ptr();
                                match typ {
                                    RenderType::FullRender => {
                                        println!("fullRender {} {}", self.buffer_width, self.buffer_height);
                                        // gl::BindTexture(gl::TEXTURE_2D, self.texture_ids[0]);
                                        // gl::TexSubImage2D(gl::TEXTURE_2D, 0,
                                        //                       0, 0,
                                        //                       self.buffer_width as i32, self.buffer_height as i32,
                                        //                       gl::RGB as u32, gl::UNSIGNED_BYTE, mem::transmute(imgbuf));
                                    },
                                    RenderType::PreviewRender => {
                                        println!("Preview {} {}", PREVIEW_WIDTH, PREVIEW_HEIGHT);
                                        // gl::BindTexture(gl::TEXTURE_2D, self.texture_ids[1]);
                                        // gl::TexSubImage2D(gl::TEXTURE_2D, 0,
                                        //                       0, 0,
                                        //                       PREVIEW_WIDTH, PREVIEW_HEIGHT,
                                        //                       gl::RGB as u32, gl::UNSIGNED_BYTE, mem::transmute(imgbuf));
                                    },
                                };
                            },
                            EngineStatus::Error(code) => println!("Error {}", code),
                        },
                    _ => ()
                }
            },
            None => (),
        }
    }

    pub fn handle_window_event(&mut self, event: glium::glutin::Event) {
        println!("handle_window_event: {:?}", event);
        let cmd_ch = self.chan_wc_to_engine.as_ref().expect("no chan_wc_to_engine");
        match event {
            Event::KeyboardInput(ElementState::Released, _, Some(keycode)) => {
                match keycode {
                    VirtualKeyCode::Space => {
                        cmd_ch.send(EngineCommand::Render(RenderType::FullRender));
                    },
                    VirtualKeyCode::Equals => {
                        cmd_ch.send(EngineCommand::ZoomIn);
                        cmd_ch.send(EngineCommand::Render(RenderType::PreviewRender));
                    },
                    VirtualKeyCode::Minus => {
                        cmd_ch.send(EngineCommand::ZoomOut);
                        cmd_ch.send(EngineCommand::Render(RenderType::PreviewRender));
                    },
                    VirtualKeyCode::Left => {
                        cmd_ch.send(EngineCommand::PanLeft);
                        cmd_ch.send(EngineCommand::Render(RenderType::PreviewRender));
                    },
                    VirtualKeyCode::Right => {
                        cmd_ch.send(EngineCommand::PanRight);
                        cmd_ch.send(EngineCommand::Render(RenderType::PreviewRender));
                    },
                    VirtualKeyCode::Up => {
                        cmd_ch.send(EngineCommand::PanUp);
                        cmd_ch.send(EngineCommand::Render(RenderType::PreviewRender));
                    },
                    VirtualKeyCode::Down => {
                        cmd_ch.send(EngineCommand::PanDown);
                        cmd_ch.send(EngineCommand::Render(RenderType::PreviewRender));
                    },
                    VirtualKeyCode::Escape => {
                        cmd_ch.send(EngineCommand::Shutdown);
//                        self.window.set_should_close(true);
                    },
                    VirtualKeyCode::S => {
                    //     match self.image {
                    //         Some(ref img) => save_as_pgm(img, self.buffer_width, self.buffer_height, "test.pgm"),
                    //         _ => (),
                    //     }
                    },
                    _ => {}
                };
            },
            _ => {},
        }
    }
}
<commit_msg>Start adding dynamic image for drawing buffer<commit_after>//============================================================================
//
// A simple Mandelbrot image generator in Rust
//
// Glutin/Glium GUI Front-end
//
// Copyright (c) 2014 Gavin Baker <gavinb@antonym.org>
// Published under the MIT license
//
//============================================================================

#![allow(unused_must_use)]

use std::sync::mpsc::{channel, Sender, Receiver};
use std::vec::Vec;
use std::thread;
use std::io::Cursor;

use glium;
use glium::{Display, Surface};
use glium::glutin::{Event,VirtualKeyCode,ElementState};
use glium::backend::glutin_backend::GlutinFacade;
use image;

use engine::MandelEngine;
use protocol::{RenderType, EngineCommand, EngineStatus, PREVIEW_WIDTH, PREVIEW_HEIGHT};
use shaders;

//----------------------------------------------------------------------------

pub struct WindowController<'a> {
    window: &'a mut GlutinFacade,
    buffer_width: u32,
    buffer_height: u32,
    chan_wc_to_engine: Option<Sender<EngineCommand>>,
    chan_wc_from_engine: Option<Receiver<EngineStatus>>,
    chan_engine_to_wc: Option<Sender<EngineStatus>>,
    chan_engine_from_wc: Option<Receiver<EngineCommand>>,
    image_buf: image::DynamicImage,
    shader_program: glium::Program,
    texture: glium::Texture2d,
}

impl<'a> WindowController<'a> {
    pub fn new(window: &'a mut GlutinFacade) -> WindowController<'a> {

        // WindowController === Engine
        // (Sender<T>, Receiver<T>)
        // x_to_y == sender
        // x_from_y == receiver
        let (chan_wc_to_engine, chan_engine_from_wc) = channel();
        let (chan_engine_to_wc, chan_wc_from_engine) = channel();

        // Size image buffer to frame
        let (w, h) =  window.get_framebuffer_dimensions();
        println!("framebuffer: w={} h={}", w, h);

        let mut image_buf = image::DynamicImage::new_rgb8(w, h);

        // Load sample image into teture for render test
        let image_dimensions = (w, h);
        let image = glium::texture::RawImage2d::from_raw_rgba_reversed(image_buf.raw_pixels(), image_dimensions);
        let texture = glium::texture::Texture2d::new(window, image).unwrap();

        // Build shaders
        let program = glium::Program::from_source(window,
                                                  shaders::VERTEX_SHADER_SOURCE,
                                                  shaders::FRAGMENT_SHADER_SOURCE,
                                                  None).unwrap();

        let mut wc = WindowController { window: window,
                                        buffer_width: w,
                                        buffer_height: h,
                                        chan_wc_to_engine: Some(chan_wc_to_engine),
                                        chan_wc_from_engine: Some(chan_wc_from_engine),
                                        chan_engine_to_wc: Some(chan_engine_to_wc),
                                        chan_engine_from_wc: Some(chan_engine_from_wc),
                                        image_buf: image_buf,
                                        shader_program: program,
                                        texture: texture,
        };

        wc
    }

    pub fn run(&mut self) {

        self.start_engine();

        loop {
            while let Some(ev) = self.window.poll_events().next() {
                self.handle_window_event(ev);
            }
            self.maybe_update_display();
            self.draw();
        }
    }

    pub fn draw(&mut self) {

        let uniforms = uniform! {
            matrix: [
                [1.0, 0.0, 0.0, 0.0],
                [0.0, 1.0, 0.0, 0.0],
                [0.0, 0.0, 1.0, 0.0],
                [0.0, 0.0, 0.0, 1.0],
            ],
            tex: &self.texture,
        };

        #[derive(Copy, Clone)]
        struct Vertex {
            position: [f32; 2],
            texcoord: [f32; 2],
        }

        implement_vertex!(Vertex, position, texcoord);

        let vertex1 = Vertex { position: [-0.5, -0.5], texcoord: [1.0, 1.0] };
        let vertex2 = Vertex { position: [ 0.0,  0.5], texcoord: [0.0, 1.0] };
        let vertex3 = Vertex { position: [ 0.5, -0.25],texcoord: [1.0, 0.0] };
        let shape = vec![vertex1, vertex2, vertex3];

        let vertex_buffer = glium::VertexBuffer::new(self.window, &shape).unwrap();
        let indices = glium::index::NoIndices(glium::index::PrimitiveType::TrianglesList);

        let mut target = self.window.draw();
        target.clear_color(0.0, 0.0, 1.0, 1.0);
        target.draw(&vertex_buffer, &indices, &self.shader_program, &uniforms,
                  &Default::default()).unwrap();
        target.finish().unwrap();
    }

    pub fn start_engine(&mut self) {

        let engine_progress_ch = self.chan_engine_to_wc.take().expect("no engine_to_wc chan");
        let engine_cmd_ch = self.chan_engine_from_wc.take().expect("no engine_from_wc chan");

        let (w,h) = (self.buffer_width, self.buffer_height);

        thread::spawn(move || {

            let mut engine = MandelEngine::new(w, h);
            engine.serve(&engine_cmd_ch, &engine_progress_ch);
        });

        let cmd_ch = self.chan_wc_to_engine.as_ref().expect("no chan_wc_to_engine");

        cmd_ch.send(EngineCommand::Render(RenderType::PreviewRender));
        cmd_ch.send(EngineCommand::Render(RenderType::FullRender));
    }

    pub fn maybe_update_display(&mut self) {
        match self.chan_wc_from_engine {
            Some(ref ch) => {
                let status_msg = ch.try_recv();
                match status_msg {
                    Ok(status) =>
                        match status {
                            EngineStatus::Startup => println!("Startup..."),
                            EngineStatus::Processing(progress) => println!("Processing {}", progress),
                            EngineStatus::RenderComplete(typ, img) => {
                                println!("Render Complete!");
                                //self.image = Some(img);
                                let imgbuf = img.as_ptr();
                                match typ {
                                    RenderType::FullRender => {
                                        println!("fullRender {} {}", self.buffer_width, self.buffer_height);
                                        // TODO: update image and texture (full size)
                                    },
                                    RenderType::PreviewRender => {
                                        println!("Preview {} {}", PREVIEW_WIDTH, PREVIEW_HEIGHT);
                                        // TODO: update image and texture (preview size)
                                    },
                                };
                            },
                            EngineStatus::Error(code) => println!("Error {}", code),
                        },
                    _ => ()
                }
            },
            None => (),
        }
    }

    pub fn handle_window_event(&mut self, event: glium::glutin::Event) {
        println!("handle_window_event: {:?}", event);
        let cmd_ch = self.chan_wc_to_engine.as_ref().expect("no chan_wc_to_engine");
        match event {
            Event::KeyboardInput(ElementState::Released, _, Some(keycode)) => {
                match keycode {
                    VirtualKeyCode::Space => {
                        cmd_ch.send(EngineCommand::Render(RenderType::FullRender));
                    },
                    VirtualKeyCode::Equals => {
                        cmd_ch.send(EngineCommand::ZoomIn);
                        cmd_ch.send(EngineCommand::Render(RenderType::PreviewRender));
                    },
                    VirtualKeyCode::Minus => {
                        cmd_ch.send(EngineCommand::ZoomOut);
                        cmd_ch.send(EngineCommand::Render(RenderType::PreviewRender));
                    },
                    VirtualKeyCode::Left => {
                        cmd_ch.send(EngineCommand::PanLeft);
                        cmd_ch.send(EngineCommand::Render(RenderType::PreviewRender));
                    },
                    VirtualKeyCode::Right => {
                        cmd_ch.send(EngineCommand::PanRight);
                        cmd_ch.send(EngineCommand::Render(RenderType::PreviewRender));
                    },
                    VirtualKeyCode::Up => {
                        cmd_ch.send(EngineCommand::PanUp);
                        cmd_ch.send(EngineCommand::Render(RenderType::PreviewRender));
                    },
                    VirtualKeyCode::Down => {
                        cmd_ch.send(EngineCommand::PanDown);
                        cmd_ch.send(EngineCommand::Render(RenderType::PreviewRender));
                    },
                    VirtualKeyCode::Escape => {
                        cmd_ch.send(EngineCommand::Shutdown);
//                        self.window.set_should_close(true);
                    },
                    VirtualKeyCode::S => {
                    //     match self.image {
                    //         Some(ref img) => save_as_pgm(img, self.buffer_width, self.buffer_height, "test.pgm"),
                    //         _ => (),
                    //     }
                    },
                    _ => {}
                };
            },
            _ => {},
        }
    }
}
<|endoftext|>


<commit_before>use libc::{c_int, c_double};
use std::ffi::CString;
use std::path::Path;
use super::super::geom::Point;
use utils::_string;
use raster::{gdal, Driver};
use raster::driver::_register_drivers;

pub struct Dataset {
    c_dataset: *const (),
}

impl Drop for Dataset {
    fn drop(&mut self) {
        unsafe { gdal::GDALClose(self.c_dataset); }
    }
}

impl Dataset {
    pub fn open(path: &Path) -> Option<Dataset> {
        _register_drivers();
        let filename = path.to_str().unwrap();
        let c_filename = CString::new(filename.as_bytes()).unwrap();
        let c_dataset = unsafe { gdal::GDALOpen(c_filename.as_ptr(), gdal::GA_READONLY) };
        return match c_dataset.is_null() {
            true  => None,
            false => Some(Dataset{c_dataset: c_dataset}),
        };
    }

    pub unsafe fn _with_c_ptr(c_dataset: *const ()) -> Dataset {
        return Dataset{c_dataset: c_dataset};
    }

    pub unsafe fn _c_ptr(&self) -> *const () {
        return self.c_dataset;
    }

    pub fn size(&self) -> (isize, isize) {
        let size_x = unsafe { gdal::GDALGetRasterXSize(self.c_dataset) } as isize;
        let size_y = unsafe { gdal::GDALGetRasterYSize(self.c_dataset) } as isize;
        return (size_x, size_y);
    }

    pub fn driver(&self) -> Driver {
        unsafe {
            let c_driver = gdal::GDALGetDatasetDriver(self.c_dataset);
            return Driver::_with_c_ptr(c_driver);
        };
    }

    pub fn count(&self) -> isize {
        return unsafe { gdal::GDALGetRasterCount(self.c_dataset) } as isize;
    }

    pub fn projection(&self) -> String {
        let rv = unsafe { gdal::GDALGetProjectionRef(self.c_dataset) };
        return _string(rv);
    }

    pub fn set_projection(&self, projection: &str) {
        let c_projection = CString::new(projection.as_bytes()).unwrap();
        unsafe { gdal::GDALSetProjection(self.c_dataset, c_projection.as_ptr()) };
    }

    pub fn set_geo_transform(&self, tr: &[f64]) {
        assert_eq!(tr.len(), 6);
        let rv = unsafe {
            gdal::GDALSetGeoTransform(self.c_dataset, tr.as_ptr())
        } as isize;
        assert!(rv == 0);
    }

    pub fn geo_transform(&self) -> Vec<f64> {
        let mut tr: Vec<c_double> = Vec::with_capacity(6);
        for _ in 0isize..6 { tr.push(0.0); }
        let rv = unsafe {
            gdal::GDALGetGeoTransform(
                self.c_dataset,
                tr.as_mut_ptr()
            )
        } as isize;
        assert!(rv == 0);
        return tr;
    }

    pub fn create_copy(
        &self,
        driver: Driver,
        filename: &str
    ) -> Option<Dataset> {
        use std::ptr::null;
        let c_filename = CString::new(filename.as_bytes()).unwrap();
        let c_dataset = unsafe { gdal::GDALCreateCopy(
                driver._c_ptr(),
                c_filename.as_ptr(),
                self.c_dataset,
                0,
                null(),
                null(),
                null()
            ) };
        return match c_dataset.is_null() {
            true  => None,
            false => Some(Dataset{c_dataset: c_dataset}),
        };
    }

    pub fn read_raster(&self,
        band_index: isize,
        window: Point<isize>,
        window_size: Point<usize>,
        size: Point<usize>
        ) -> ByteBuffer
    {
        let nbytes = size.x * size.y;
        let mut data: Vec<u8> = (0..nbytes).map(|_| 0u8).collect();
        unsafe {
            let c_band = gdal::GDALGetRasterBand(self.c_dataset, band_index as c_int);
            let rv = gdal::GDALRasterIO(
                c_band,
                gdal::GF_READ,
                window.x as c_int,
                window.y as c_int,
                window_size.x as c_int,
                window_size.y as c_int,
                data.as_mut_ptr() as *const (),
                size.x as c_int,
                size.y as c_int,
                gdal::GDT_BYTE,
                0,
                0
            ) as isize;
            assert!(rv == 0);
        };
        return ByteBuffer{
            size: size,
            data: data,
        };
    }

    pub fn write_raster(
        &self,
        band_index: isize,
        window: Point<isize>,
        window_size: Point<usize>,
        buffer: ByteBuffer
    ) {
        assert_eq!(buffer.data.len(), buffer.size.x * buffer.size.y);
        unsafe {
            let c_band = gdal::GDALGetRasterBand(self.c_dataset, band_index as c_int);
            let rv = gdal::GDALRasterIO(
                c_band,
                gdal::GF_WRITE,
                window.x as c_int,
                window.y as c_int,
                window_size.x as c_int,
                window_size.y as c_int,
                buffer.data.as_ptr() as *const (),
                buffer.size.x as c_int,
                buffer.size.y as c_int,
                gdal::GDT_BYTE,
                0,
                0
            ) as isize;
            assert!(rv == 0);
        };
    }
}

pub struct ByteBuffer {
    pub size: Point<usize>,
    pub data: Vec<u8>,
}
<commit_msg>Don't fill the Vec with zeros before reading.<commit_after>use libc::{c_int, c_double};
use std::ffi::CString;
use std::path::Path;
use super::super::geom::Point;
use utils::_string;
use raster::{gdal, Driver};
use raster::driver::_register_drivers;

pub struct Dataset {
    c_dataset: *const (),
}

impl Drop for Dataset {
    fn drop(&mut self) {
        unsafe { gdal::GDALClose(self.c_dataset); }
    }
}

impl Dataset {
    pub fn open(path: &Path) -> Option<Dataset> {
        _register_drivers();
        let filename = path.to_str().unwrap();
        let c_filename = CString::new(filename.as_bytes()).unwrap();
        let c_dataset = unsafe { gdal::GDALOpen(c_filename.as_ptr(), gdal::GA_READONLY) };
        return match c_dataset.is_null() {
            true  => None,
            false => Some(Dataset{c_dataset: c_dataset}),
        };
    }

    pub unsafe fn _with_c_ptr(c_dataset: *const ()) -> Dataset {
        return Dataset{c_dataset: c_dataset};
    }

    pub unsafe fn _c_ptr(&self) -> *const () {
        return self.c_dataset;
    }

    pub fn size(&self) -> (isize, isize) {
        let size_x = unsafe { gdal::GDALGetRasterXSize(self.c_dataset) } as isize;
        let size_y = unsafe { gdal::GDALGetRasterYSize(self.c_dataset) } as isize;
        return (size_x, size_y);
    }

    pub fn driver(&self) -> Driver {
        unsafe {
            let c_driver = gdal::GDALGetDatasetDriver(self.c_dataset);
            return Driver::_with_c_ptr(c_driver);
        };
    }

    pub fn count(&self) -> isize {
        return unsafe { gdal::GDALGetRasterCount(self.c_dataset) } as isize;
    }

    pub fn projection(&self) -> String {
        let rv = unsafe { gdal::GDALGetProjectionRef(self.c_dataset) };
        return _string(rv);
    }

    pub fn set_projection(&self, projection: &str) {
        let c_projection = CString::new(projection.as_bytes()).unwrap();
        unsafe { gdal::GDALSetProjection(self.c_dataset, c_projection.as_ptr()) };
    }

    pub fn set_geo_transform(&self, tr: &[f64]) {
        assert_eq!(tr.len(), 6);
        let rv = unsafe {
            gdal::GDALSetGeoTransform(self.c_dataset, tr.as_ptr())
        } as isize;
        assert!(rv == 0);
    }

    pub fn geo_transform(&self) -> Vec<f64> {
        let mut tr: Vec<c_double> = Vec::with_capacity(6);
        for _ in 0isize..6 { tr.push(0.0); }
        let rv = unsafe {
            gdal::GDALGetGeoTransform(
                self.c_dataset,
                tr.as_mut_ptr()
            )
        } as isize;
        assert!(rv == 0);
        return tr;
    }

    pub fn create_copy(
        &self,
        driver: Driver,
        filename: &str
    ) -> Option<Dataset> {
        use std::ptr::null;
        let c_filename = CString::new(filename.as_bytes()).unwrap();
        let c_dataset = unsafe { gdal::GDALCreateCopy(
                driver._c_ptr(),
                c_filename.as_ptr(),
                self.c_dataset,
                0,
                null(),
                null(),
                null()
            ) };
        return match c_dataset.is_null() {
            true  => None,
            false => Some(Dataset{c_dataset: c_dataset}),
        };
    }

    pub fn read_raster(&self,
        band_index: isize,
        window: Point<isize>,
        window_size: Point<usize>,
        size: Point<usize>
        ) -> ByteBuffer
    {
        let nbytes = size.x * size.y;
        let mut data: Vec<u8> = Vec::with_capacity(nbytes);
        unsafe {
            let c_band = gdal::GDALGetRasterBand(self.c_dataset, band_index as c_int);
            let rv = gdal::GDALRasterIO(
                c_band,
                gdal::GF_READ,
                window.x as c_int,
                window.y as c_int,
                window_size.x as c_int,
                window_size.y as c_int,
                data.as_mut_ptr() as *const (),
                size.x as c_int,
                size.y as c_int,
                gdal::GDT_BYTE,
                0,
                0
            ) as isize;
            assert!(rv == 0);
            data.set_len(nbytes);
        };
        return ByteBuffer{
            size: size,
            data: data,
        };
    }

    pub fn write_raster(
        &self,
        band_index: isize,
        window: Point<isize>,
        window_size: Point<usize>,
        buffer: ByteBuffer
    ) {
        assert_eq!(buffer.data.len(), buffer.size.x * buffer.size.y);
        unsafe {
            let c_band = gdal::GDALGetRasterBand(self.c_dataset, band_index as c_int);
            let rv = gdal::GDALRasterIO(
                c_band,
                gdal::GF_WRITE,
                window.x as c_int,
                window.y as c_int,
                window_size.x as c_int,
                window_size.y as c_int,
                buffer.data.as_ptr() as *const (),
                buffer.size.x as c_int,
                buffer.size.y as c_int,
                gdal::GDT_BYTE,
                0,
                0
            ) as isize;
            assert!(rv == 0);
        };
    }
}

pub struct ByteBuffer {
    pub size: Point<usize>,
    pub data: Vec<u8>,
}
<|endoftext|>


<commit_before>use std::cmp::Ordering;
use std::cmp::Ordering::{ Equal, Less, Greater };
use std::num::Int;
use std::slice;

use iter::{ self, Iter, UnionIter, IntersectionIter, DifferenceIter, SymmetricDifferenceIter };
use container::Container;
use util;
use util::{ Halveable, ExtInt };

type RB<Size> = ::RoaringBitmap<Size>;

#[inline]
pub fn new<Size: ExtInt + Halveable>() -> RB<Size> {
    RB { containers: Vec::new() }
}

pub fn insert<Size: ExtInt + Halveable>(this: &mut RB<Size>, value: Size) -> bool {
    let (key, index) = value.split();
    let container = match this.containers.binary_search_by(|container| container.key().cmp(&key)) {
        Ok(loc) => &mut this.containers[loc],
        Err(loc) => {
            this.containers.insert(loc, Container::new(key));
            &mut this.containers[loc]
        },
    };
    container.insert(index)
}

pub fn remove<Size: ExtInt + Halveable>(this: &mut RB<Size>, value: Size) -> bool {
    let (key, index) = value.split();
    match this.containers.binary_search_by(|container| container.key().cmp(&key)) {
        Ok(loc) => {
            if this.containers[loc].remove(index) {
                if this.containers[loc].len() == Int::zero() {
                    this.containers.remove(loc);
                }
                true
            } else {
                false
            }
        }
        _ => false,
    }
}

pub fn contains<Size: ExtInt + Halveable>(this: &RB<Size>, value: Size) -> bool {
    let (key, index) = value.split();
    match this.containers.binary_search_by(|container| container.key().cmp(&key)) {
        Ok(loc) => this.containers[loc].contains(index),
        Err(_) => false,
    }
}

#[inline]
pub fn clear<Size: ExtInt + Halveable>(this: &mut RB<Size>) {
    this.containers.clear();
}

#[inline]
pub fn is_empty<Size: ExtInt + Halveable>(this: &RB<Size>) -> bool {
    this.containers.is_empty()
}

pub fn len<Size: ExtInt + Halveable>(this: &RB<Size>) -> Size {
    this.containers
        .iter()
        .map(|container| container.len())
        .fold(Int::zero(), |sum: Size, len| sum + util::cast(len))
}

#[inline]
pub fn iter<'a, Size: ExtInt + Halveable>(this: &'a RB<Size>) -> Iter<'a, Size> where <Size as Halveable>::HalfSize : 'a {
    iter::new(this.containers.iter())
}

fn pairs<'a, Size: ExtInt + Halveable>(this: &'a RB<Size>, other: &'a RB<Size>) -> Pairs<'a, Size> where <Size as Halveable>::HalfSize : 'a {
    Pairs::new(this.containers.iter(), other.containers.iter())
}

pub fn is_disjoint<Size: ExtInt + Halveable>(this: &RB<Size>, other: &RB<Size>) -> bool {
    pairs(this, other)
        .filter(|&(c1, c2)| c1.is_some() && c2.is_some())
        .all(|(c1, c2)| c1.unwrap().is_disjoint(c2.unwrap()))
}

pub fn is_subset<Size: ExtInt + Halveable>(this: &RB<Size>, other: &RB<Size>) -> bool {
    pairs(this, other).all(|pairs| match pairs {
        (None, _) => return true,
        (_, None) => return false,
        (Some(c1), Some(c2)) => c1.is_subset(c2),
    })
}

#[inline]
pub fn is_superset<Size: ExtInt + Halveable>(this: &RB<Size>, other: &RB<Size>) -> bool {
    other.is_subset(this)
}

#[inline]
pub fn union<'a, Size: ExtInt + Halveable>(this: &'a RB<Size>, other: &'a RB<Size>) -> UnionIter<'a, Size> where <Size as Halveable>::HalfSize : 'a {
    iter::union::new(this.iter(), other.iter())
}

#[inline]
pub fn intersection<'a, Size: ExtInt + Halveable>(this: &'a RB<Size>, other: &'a RB<Size>) -> IntersectionIter<'a, Size> where <Size as Halveable>::HalfSize : 'a {
    iter::intersection::new(this.iter(), other.iter())
}

#[inline]
pub fn difference<'a, Size: ExtInt + Halveable>(this: &'a RB<Size>, other: &'a RB<Size>) -> DifferenceIter<'a, Size> where <Size as Halveable>::HalfSize : 'a {
    iter::difference::new(this.iter(), other.iter())
}

#[inline]
pub fn symmetric_difference<'a, Size: ExtInt + Halveable>(this: &'a RB<Size>, other: &'a RB<Size>) -> SymmetricDifferenceIter<'a, Size> where <Size as Halveable>::HalfSize : 'a {
    iter::symmetric_difference::new(this.iter(), other.iter())
}

#[inline]
pub fn union_with<Size: ExtInt + Halveable>(this: &mut RB<Size>, other: &RB<Size>) {
    for container in other.containers.iter() {
        let key = container.key();
        match this.containers.binary_search_by(|container| container.key().cmp(&key)) {
            Err(loc) => this.containers.insert(loc, (*container).clone()),
            Ok(loc) => this.containers[loc].union_with(container),
        };
    }
}

#[inline]
pub fn intersect_with<Size: ExtInt + Halveable>(this: &mut RB<Size>, other: &RB<Size>) {
    let mut index = 0;
    while index < this.containers.len() {
        let key = this.containers[index].key();
        match other.containers.binary_search_by(|container| container.key().cmp(&key)) {
            Err(_) => {
                this.containers.remove(index);
            },
            Ok(loc) => {
                this.containers[index].intersect_with(&other.containers[loc]);
                index += 1;
            },
        };
    }
}

#[inline]
pub fn difference_with<Size: ExtInt + Halveable>(this: &mut RB<Size>, other: &RB<Size>) {
    for index in 0..this.containers.len() {
        let key = this.containers[index].key();
        match other.containers.binary_search_by(|container| container.key().cmp(&key)) {
            Ok(loc) => {
                this.containers[index].difference_with(&other.containers[loc]);
                if this.containers[index].len() == Int::zero() {
                    this.containers.remove(index);
                }
            },
            _ => (),
        };
    }
}

#[inline]
pub fn symmetric_difference_with<Size: ExtInt + Halveable>(this: &mut RB<Size>, other: &RB<Size>) {
    for container in other.containers.iter() {
        let key = container.key();
        match this.containers.binary_search_by(|container| container.key().cmp(&key)) {
            Err(loc) => this.containers.insert(loc, (*container).clone()),
            Ok(loc) => {
                this.containers[loc].symmetric_difference_with(container);
                if this.containers[loc].len() == Int::zero() {
                    this.containers.remove(loc);
                }
            }
        };
    }
}

#[inline]
pub fn from_iter<Size: ExtInt + Halveable, I: Iterator<Item = Size>>(iterator: I) -> RB<Size> {
    let mut rb = new();
    rb.extend(iterator);
    rb
}

#[inline]
pub fn from_iter_ref<'a, Size: ExtInt + Halveable + 'a, I: Iterator<Item = &'a Size>>(iterator: I) -> RB<Size> {
    let mut rb = new();
    rb.extend(iterator);
    rb
}

#[inline]
pub fn extend<Size: ExtInt + Halveable, I: Iterator<Item = Size>>(this: &mut RB<Size>, mut iterator: I) {
    for value in iterator {
        this.insert(value);
    }
}

#[inline]
pub fn extend_ref<'a, Size: ExtInt + Halveable + 'a, I: Iterator<Item = &'a Size>>(this: &mut RB<Size>, mut iterator: I) {
    for value in iterator {
        this.insert(*value);
    }
}

pub fn min<Size: ExtInt + Halveable>(this: &RB<Size>) -> Size {
    match &this.containers[] {
        [ref head, ..] => Halveable::join(head.key(), head.min()),
        [] => Int::min_value(),
    }
}

pub fn max<Size: ExtInt + Halveable>(this: &RB<Size>) -> Size {
    match &this.containers[] {
        [.., ref tail] => Halveable::join(tail.key(), tail.max()),
        [] => Int::max_value(),
    }
}

struct Pairs<'a, Size: ExtInt + Halveable + 'a> where <Size as Halveable>::HalfSize : 'a {
    iter1: slice::Iter<'a, Container<<Size as Halveable>::HalfSize>>,
    iter2: slice::Iter<'a, Container<<Size as Halveable>::HalfSize>>,
    current1: Option<&'a Container<<Size as Halveable>::HalfSize>>,
    current2: Option<&'a Container<<Size as Halveable>::HalfSize>>,
}

impl<'a, Size: ExtInt + Halveable> Pairs<'a, Size> {
    fn new(mut iter1: slice::Iter<'a, Container<<Size as Halveable>::HalfSize>>, mut iter2: slice::Iter<'a, Container<<Size as Halveable>::HalfSize>>) -> Pairs<'a, Size> {
        Pairs {
            iter1: iter1,
            iter2: iter2,
            current1: iter1.next(),
            current2: iter2.next(),
        }
    }
}

impl<'a, Size: ExtInt + Halveable> Iterator for Pairs<'a, Size> {
    type Item = (Option<&'a Container<<Size as Halveable>::HalfSize>>, Option<&'a Container<<Size as Halveable>::HalfSize>>);

    fn next(&mut self) -> Option<(Option<&'a Container<<Size as Halveable>::HalfSize>>, Option<&'a Container<<Size as Halveable>::HalfSize>>)> {
        match (self.current1, self.current2) {
            (None, None) => None,
            (Some(c1), None) => {
                self.current1 = self.iter1.next();
                Some((Some(c1), None))
            },
            (None, Some(c2)) => {
                self.current2 = self.iter2.next();
                Some((None, Some(c2)))
            },
            (Some(c1), Some(c2)) => match (c1.key(), c2.key()) {
                (key1, key2) if key1 == key2 => {
                    self.current1 = self.iter1.next();
                    self.current2 = self.iter2.next();
                    Some((Some(c1), Some(c2)))
                },
                (key1, key2) if key1 < key2 => {
                    self.current1 = self.iter1.next();
                    Some((Some(c1), None))
                },
                (key1, key2) if key1 > key2 => {
                    self.current2 = self.iter2.next();
                    Some((None, Some(c2)))
                },
                (_, _) => panic!(),
            }
        }
    }
}
<commit_msg>Fix use after move<commit_after>use std::cmp::Ordering;
use std::cmp::Ordering::{ Equal, Less, Greater };
use std::num::Int;
use std::slice;

use iter::{ self, Iter, UnionIter, IntersectionIter, DifferenceIter, SymmetricDifferenceIter };
use container::Container;
use util;
use util::{ Halveable, ExtInt };

type RB<Size> = ::RoaringBitmap<Size>;

#[inline]
pub fn new<Size: ExtInt + Halveable>() -> RB<Size> {
    RB { containers: Vec::new() }
}

pub fn insert<Size: ExtInt + Halveable>(this: &mut RB<Size>, value: Size) -> bool {
    let (key, index) = value.split();
    let container = match this.containers.binary_search_by(|container| container.key().cmp(&key)) {
        Ok(loc) => &mut this.containers[loc],
        Err(loc) => {
            this.containers.insert(loc, Container::new(key));
            &mut this.containers[loc]
        },
    };
    container.insert(index)
}

pub fn remove<Size: ExtInt + Halveable>(this: &mut RB<Size>, value: Size) -> bool {
    let (key, index) = value.split();
    match this.containers.binary_search_by(|container| container.key().cmp(&key)) {
        Ok(loc) => {
            if this.containers[loc].remove(index) {
                if this.containers[loc].len() == Int::zero() {
                    this.containers.remove(loc);
                }
                true
            } else {
                false
            }
        }
        _ => false,
    }
}

pub fn contains<Size: ExtInt + Halveable>(this: &RB<Size>, value: Size) -> bool {
    let (key, index) = value.split();
    match this.containers.binary_search_by(|container| container.key().cmp(&key)) {
        Ok(loc) => this.containers[loc].contains(index),
        Err(_) => false,
    }
}

#[inline]
pub fn clear<Size: ExtInt + Halveable>(this: &mut RB<Size>) {
    this.containers.clear();
}

#[inline]
pub fn is_empty<Size: ExtInt + Halveable>(this: &RB<Size>) -> bool {
    this.containers.is_empty()
}

pub fn len<Size: ExtInt + Halveable>(this: &RB<Size>) -> Size {
    this.containers
        .iter()
        .map(|container| container.len())
        .fold(Int::zero(), |sum: Size, len| sum + util::cast(len))
}

#[inline]
pub fn iter<'a, Size: ExtInt + Halveable>(this: &'a RB<Size>) -> Iter<'a, Size> where <Size as Halveable>::HalfSize : 'a {
    iter::new(this.containers.iter())
}

fn pairs<'a, Size: ExtInt + Halveable>(this: &'a RB<Size>, other: &'a RB<Size>) -> Pairs<'a, Size> where <Size as Halveable>::HalfSize : 'a {
    Pairs::new(this.containers.iter(), other.containers.iter())
}

pub fn is_disjoint<Size: ExtInt + Halveable>(this: &RB<Size>, other: &RB<Size>) -> bool {
    pairs(this, other)
        .filter(|&(c1, c2)| c1.is_some() && c2.is_some())
        .all(|(c1, c2)| c1.unwrap().is_disjoint(c2.unwrap()))
}

pub fn is_subset<Size: ExtInt + Halveable>(this: &RB<Size>, other: &RB<Size>) -> bool {
    pairs(this, other).all(|pairs| match pairs {
        (None, _) => return true,
        (_, None) => return false,
        (Some(c1), Some(c2)) => c1.is_subset(c2),
    })
}

#[inline]
pub fn is_superset<Size: ExtInt + Halveable>(this: &RB<Size>, other: &RB<Size>) -> bool {
    other.is_subset(this)
}

#[inline]
pub fn union<'a, Size: ExtInt + Halveable>(this: &'a RB<Size>, other: &'a RB<Size>) -> UnionIter<'a, Size> where <Size as Halveable>::HalfSize : 'a {
    iter::union::new(this.iter(), other.iter())
}

#[inline]
pub fn intersection<'a, Size: ExtInt + Halveable>(this: &'a RB<Size>, other: &'a RB<Size>) -> IntersectionIter<'a, Size> where <Size as Halveable>::HalfSize : 'a {
    iter::intersection::new(this.iter(), other.iter())
}

#[inline]
pub fn difference<'a, Size: ExtInt + Halveable>(this: &'a RB<Size>, other: &'a RB<Size>) -> DifferenceIter<'a, Size> where <Size as Halveable>::HalfSize : 'a {
    iter::difference::new(this.iter(), other.iter())
}

#[inline]
pub fn symmetric_difference<'a, Size: ExtInt + Halveable>(this: &'a RB<Size>, other: &'a RB<Size>) -> SymmetricDifferenceIter<'a, Size> where <Size as Halveable>::HalfSize : 'a {
    iter::symmetric_difference::new(this.iter(), other.iter())
}

#[inline]
pub fn union_with<Size: ExtInt + Halveable>(this: &mut RB<Size>, other: &RB<Size>) {
    for container in other.containers.iter() {
        let key = container.key();
        match this.containers.binary_search_by(|container| container.key().cmp(&key)) {
            Err(loc) => this.containers.insert(loc, (*container).clone()),
            Ok(loc) => this.containers[loc].union_with(container),
        };
    }
}

#[inline]
pub fn intersect_with<Size: ExtInt + Halveable>(this: &mut RB<Size>, other: &RB<Size>) {
    let mut index = 0;
    while index < this.containers.len() {
        let key = this.containers[index].key();
        match other.containers.binary_search_by(|container| container.key().cmp(&key)) {
            Err(_) => {
                this.containers.remove(index);
            },
            Ok(loc) => {
                this.containers[index].intersect_with(&other.containers[loc]);
                index += 1;
            },
        };
    }
}

#[inline]
pub fn difference_with<Size: ExtInt + Halveable>(this: &mut RB<Size>, other: &RB<Size>) {
    for index in 0..this.containers.len() {
        let key = this.containers[index].key();
        match other.containers.binary_search_by(|container| container.key().cmp(&key)) {
            Ok(loc) => {
                this.containers[index].difference_with(&other.containers[loc]);
                if this.containers[index].len() == Int::zero() {
                    this.containers.remove(index);
                }
            },
            _ => (),
        };
    }
}

#[inline]
pub fn symmetric_difference_with<Size: ExtInt + Halveable>(this: &mut RB<Size>, other: &RB<Size>) {
    for container in other.containers.iter() {
        let key = container.key();
        match this.containers.binary_search_by(|container| container.key().cmp(&key)) {
            Err(loc) => this.containers.insert(loc, (*container).clone()),
            Ok(loc) => {
                this.containers[loc].symmetric_difference_with(container);
                if this.containers[loc].len() == Int::zero() {
                    this.containers.remove(loc);
                }
            }
        };
    }
}

#[inline]
pub fn from_iter<Size: ExtInt + Halveable, I: Iterator<Item = Size>>(iterator: I) -> RB<Size> {
    let mut rb = new();
    rb.extend(iterator);
    rb
}

#[inline]
pub fn from_iter_ref<'a, Size: ExtInt + Halveable + 'a, I: Iterator<Item = &'a Size>>(iterator: I) -> RB<Size> {
    let mut rb = new();
    rb.extend(iterator);
    rb
}

#[inline]
pub fn extend<Size: ExtInt + Halveable, I: Iterator<Item = Size>>(this: &mut RB<Size>, mut iterator: I) {
    for value in iterator {
        this.insert(value);
    }
}

#[inline]
pub fn extend_ref<'a, Size: ExtInt + Halveable + 'a, I: Iterator<Item = &'a Size>>(this: &mut RB<Size>, mut iterator: I) {
    for value in iterator {
        this.insert(*value);
    }
}

pub fn min<Size: ExtInt + Halveable>(this: &RB<Size>) -> Size {
    match &this.containers[] {
        [ref head, ..] => Halveable::join(head.key(), head.min()),
        [] => Int::min_value(),
    }
}

pub fn max<Size: ExtInt + Halveable>(this: &RB<Size>) -> Size {
    match &this.containers[] {
        [.., ref tail] => Halveable::join(tail.key(), tail.max()),
        [] => Int::max_value(),
    }
}

struct Pairs<'a, Size: ExtInt + Halveable + 'a> where <Size as Halveable>::HalfSize : 'a {
    iter1: slice::Iter<'a, Container<<Size as Halveable>::HalfSize>>,
    iter2: slice::Iter<'a, Container<<Size as Halveable>::HalfSize>>,
    current1: Option<&'a Container<<Size as Halveable>::HalfSize>>,
    current2: Option<&'a Container<<Size as Halveable>::HalfSize>>,
}

impl<'a, Size: ExtInt + Halveable> Pairs<'a, Size> {
    fn new(mut iter1: slice::Iter<'a, Container<<Size as Halveable>::HalfSize>>, mut iter2: slice::Iter<'a, Container<<Size as Halveable>::HalfSize>>) -> Pairs<'a, Size> {
        let (current1, current2) = (iter1.next(), iter2.next());
        Pairs {
            iter1: iter1,
            iter2: iter2,
            current1: current1,
            current2: current2,
        }
    }
}

impl<'a, Size: ExtInt + Halveable> Iterator for Pairs<'a, Size> {
    type Item = (Option<&'a Container<<Size as Halveable>::HalfSize>>, Option<&'a Container<<Size as Halveable>::HalfSize>>);

    fn next(&mut self) -> Option<(Option<&'a Container<<Size as Halveable>::HalfSize>>, Option<&'a Container<<Size as Halveable>::HalfSize>>)> {
        match (self.current1, self.current2) {
            (None, None) => None,
            (Some(c1), None) => {
                self.current1 = self.iter1.next();
                Some((Some(c1), None))
            },
            (None, Some(c2)) => {
                self.current2 = self.iter2.next();
                Some((None, Some(c2)))
            },
            (Some(c1), Some(c2)) => match (c1.key(), c2.key()) {
                (key1, key2) if key1 == key2 => {
                    self.current1 = self.iter1.next();
                    self.current2 = self.iter2.next();
                    Some((Some(c1), Some(c2)))
                },
                (key1, key2) if key1 < key2 => {
                    self.current1 = self.iter1.next();
                    Some((Some(c1), None))
                },
                (key1, key2) if key1 > key2 => {
                    self.current2 = self.iter2.next();
                    Some((None, Some(c2)))
                },
                (_, _) => panic!(),
            }
        }
    }
}
<|endoftext|>