<commit_before>extern crate libc;

use x11::xlib;
use x11::xlib::Window;
use super::super::libx;

use super::config::Config;
use super::Container;
use super::Workspaces;
use super::handler;

unsafe extern fn error_handler(display: *mut xlib::Display, event: *mut xlib::XErrorEvent) -> libc::c_int {
    // match event.error_code {
    //     xlib::BadAtom => {
    //         println!("bad atom");
    //     }
    //     _ => {}
    // }
    1
}

pub struct WindowManager {
    pub context: libx::Context,
    pub workspaces: Workspaces,
    config: Config
}

impl WindowManager {
    pub fn new() -> WindowManager {
	let res = libx::open_display(None);
        let mut context = match res {
            Some(c) => {
                c
            }
            None => {
                panic!("can't open display")
            }
        };

	context.screen_num  = libx::default_screen(context);
	context.root = libx::root_window(context, context.screen_num);

	let mut wm = WindowManager {
            context: context,
            config: Config::load(),
            workspaces: Workspaces::new(context)
        };
        wm.workspaces.create('1');
        wm.workspaces.get('1').unwrap().visible = true;
        wm.workspaces.switch_current('1', context);
        wm
    }

    pub fn clean(&mut self) {
        libx::close_display(self.context);
    }

    pub fn handle_create(&mut self, event: &xlib::XCreateWindowEvent) {
        if event.override_redirect != 0 {
            return;
        }

        let attrs = libx::get_window_attributes(self.context, event.window);
        println!("{} attr {} {}", event.window, attrs.width, attrs.height);
        // get window property
        let n = libx::get_text_property(self.context, event.window, xlib::XA_WM_NAME);
        match n {
            Some(s) => {debug!("create window {} for {}", event.window, s);}
            None => {}
        }

        // let atoms = libx::get_wm_protocols(self.context, event.window);
        // for a in atoms.iter() {
        //     println!("atom {}", a);
        //     let name = libx::get_atom_name(self.context, *a);
        //     match name {
        //         Some(n) => println!("name {}", n),
        //         None => println!("name {}", a),
        //     };
        // }
    }

    pub fn handle_destroy(&mut self, event: &xlib::XDestroyWindowEvent) {
        self.workspaces.remove_window(event.window);
        if self.workspaces.get_focus().is_none() {
            self.workspaces.set_focus(self.context.root);
        }
    }

    pub fn handle_map_request(&mut self, event: &xlib::XMapRequestEvent) {

        // add app top-level window to workspace
        // let window = Window::new(self.context, event.window);
        let manage = Workspaces::can_manage(self.context, event.window);

        if manage {
            debug!("top level window");
            let mut container = Container::from_id(self.context, event.window);
            container.map();
            container.focus();
            // change attributes before display
            let mask = 0x420010;
            let mask = xlib::EnterWindowMask | xlib::PropertyChangeMask;
            libx::select_input(self.context, container.id, mask);

            if self.config.titlebar_height > 0 {
                container.titlebar_height = self.config.titlebar_height as usize;
            }
            self.workspaces.add_window(container, None);
        }
        else {
            libx::map_window(self.context, event.window);
        }
    }

    pub fn handle_client_message(&mut self, event: &xlib::XClientMessageEvent) {
        println!("message type {}", event.message_type);
        let s = libx::get_atom_name(self.context, event.message_type);
        match s {
            Some(v) => println!("{}", &v),
            None => {}
        }

        match event.format {
            8 => {
                for i in 0..20 {
                    println!("{}", event.data.get_byte(i));
                }
            }
            16 => {
                for i in 0..10 {
                    println!("{}", event.data.get_short(i))
                }
            }
            32 => {
                for i in 0..5 {
                    let a = event.data.get_long(i);
                    if a != 0{
                        let s = libx::get_atom_name(self.context, a as xlib::Atom);
                        match s {
                            Some(v) => println!("{}", v),
                            None => {}
                        }
                    }
                }
            }
            _ => {}
        }
    }

    pub fn handle_button_motion(&mut self, event: &xlib::XMotionEvent) {
        let (window, _) = libx::get_input_focus(self.context);
        if window != event.window {
            self.workspaces.set_focus(event.window);
        }
    }

    pub fn handle_key_release(&mut self, event: &xlib::XKeyEvent) {
        if event.state > 0 {
            let sym = libx::lookup_keysym(*event, 0);
            let b = handler::KeyBind {
                key: sym,
                mask: event.state,
            };
            debug!("key {} {}", event.state, sym);

            match self.config.bindsyms.get_mut(&b) {
                Some(handler) => {
                    handler.handle(&mut self.workspaces, self.context);
                }
                None => {
                    println!("no bind");
                }
            }
        }
    }

    pub fn handle_property(&mut self, event: &xlib::XPropertyEvent) {
        let usertime = libx::get_atom(self.context, "_NET_WM_USER_TIME");
        match event.atom {
            usertime => {
                debug!("_NET_WM_USER_TIME");
                // let window = Window::new(self.context, event.window);
                self.workspaces.set_focus(event.window);
            }
        }
    }

    pub fn handle_configure_request(&mut self, event: &xlib::XConfigureRequestEvent) {
        let mut change = xlib::XWindowChanges {
            x: event.x,
            y: event.y,
            width: event.width,
            height: event.height,
            border_width: event.border_width,
            sibling: event.above,
            stack_mode: event.detail
        };
        debug!("config x: {}, y: {}, width: {}, height: {}",
               change.x, change.y, change.width, change.height);
        libx::configure_window(self.context, event.window, event.value_mask as u32, change);
    }

    pub fn handle_focus_in(&mut self, event: &xlib::XFocusChangeEvent) {
        self.workspaces.set_focus(event.window);
      }

    pub fn handle_enter(&mut self, event: &xlib::XCrossingEvent){
        if event.focus == 0 {
            self.workspaces.set_focus(event.window);
        }
    }

    pub fn handle(&mut self, e: xlib::XEvent) {
        let t = e.get_type();
        match t {
            xlib::CreateNotify => {
                let event: xlib::XCreateWindowEvent = From::from(e);
                debug!("create notify {}", event.window);
                self.handle_create(&event);
            }
            xlib::DestroyNotify => {
                let event: xlib::XDestroyWindowEvent = From::from(e);
                debug!("destroy notify {}", event.window);
                self.handle_destroy(&event);
            }
            xlib::MapNotify => {
                let event: xlib::XMapEvent = From::from(e);
                debug!("map notify {}", event.window);
            }
            xlib::UnmapNotify => {
                let event: xlib::XUnmapEvent = From::from(e);
                debug!("unmap notify {}", event.window);
            }
            xlib::MapRequest => {
                let event: xlib::XMapRequestEvent = From::from(e);
                debug!("map request {}", event.window);
                self.handle_map_request(&event);
            }
            xlib::ClientMessage => {
                debug!("client message");
                // let event = cast_event::<xlib::XClientMessageEvent>(&e);
                let event: xlib::XClientMessageEvent = From::from(e);
                self.handle_client_message(&event);
            }
            xlib::KeyRelease => {
                debug!("key release");
                let mut event: xlib::XKeyEvent = From::from(e);
                self.handle_key_release(&mut event);
            }
            xlib::MotionNotify => {
                let mut event: xlib::XMotionEvent = From::from(e);
                debug!("button motion {}", event.window);
                self.handle_button_motion(&event);
            }
            xlib::ButtonRelease => {
                let mut event: xlib::XButtonEvent = From::from(e);
                debug!("button release {}", event.window);
            }
            xlib::ButtonPress => {
                let mut event: xlib::XButtonEvent = From::from(e);
                debug!("button press {}", event.window);
            }
            xlib::ConfigureNotify => {
                debug!("configure notify");
            }
            xlib::ConfigureRequest =>{
                let mut event: xlib::XConfigureRequestEvent = From::from(e);
                debug!("configure request {}", event.window);
                self.handle_configure_request(&event);
            }
            xlib::FocusIn => {
                let mut event: xlib::XFocusChangeEvent = From::from(e);
                debug!("focus in {}", event.window);
                self.handle_focus_in(&event);

            }
            xlib::FocusOut => {
                let mut event: xlib::XFocusChangeEvent = From::from(e);
                debug!("focus out {}", event.window);
            }
            xlib::EnterNotify => {
                let mut event: xlib::XCrossingEvent = From::from(e);
                debug!("enter window {}", event.window);
                self.handle_enter(&event);
            }
            xlib::PropertyNotify => {
                let mut event: xlib::XPropertyEvent = From::from(e);
                debug!("property notify {}", event.window);
                self.handle_property(&event);
            }
            _ => {
                debug!("unhandled event {}", t);
            }
        }
    }
    pub fn run(&mut self) {
        loop {
            //handle events here
            let mut e = libx::next_event(self.context);
            self.handle(e);
        }
    }

    pub fn init(&mut self) {
        let mask = 0x1A0034;
        let mask = xlib::SubstructureRedirectMask | xlib::SubstructureNotifyMask;

        unsafe{
            // xlib::XSetErrorHandler(Some(error_handler));
        }
        let left_ptr: u32 = 68;
        libx::define_cursor(self.context, self.context.root, left_ptr);

        libx::ungrab_button(self.context, 0, 0x8000, self.context.root);
        libx::select_input(self.context, self.context.root,
                           mask);

        for bind in self.config.bindsyms.keys() {
            let code = libx::keysym_to_keycode(self.context, bind.key);
            libx::grab_key(self.context, code, bind.mask, self.context.root);
        }
        libx::sync(self.context, 0);
    }
}
<commit_msg>init workspaces<commit_after>extern crate libc;

use x11::xlib;
use x11::xlib::Window;
use super::super::libx;

use super::config::Config;
use super::Container;
use super::Workspaces;
use super::handler;

unsafe extern fn error_handler(display: *mut xlib::Display, event: *mut xlib::XErrorEvent) -> libc::c_int {
    // match event.error_code {
    //     xlib::BadAtom => {
    //         println!("bad atom");
    //     }
    //     _ => {}
    // }
    1
}

pub struct WindowManager {
    pub context: libx::Context,
    pub workspaces: Workspaces,
    config: Config
}

impl WindowManager {
    pub fn new() -> WindowManager {
	let res = libx::open_display(None);
        let mut context = match res {
            Some(c) => {
                c
            }
            None => {
                panic!("can't open display")
            }
        };

	context.screen_num  = libx::default_screen(context);
	context.root = libx::root_window(context, context.screen_num);

	let mut wm = WindowManager {
            context: context,
            config: Config::load(),
            workspaces: Workspaces::new(context)
        };
        wm
    }

    pub fn clean(&mut self) {
        libx::close_display(self.context);
    }

    pub fn handle_create(&mut self, event: &xlib::XCreateWindowEvent) {
        if event.override_redirect != 0 {
            return;
        }

        let attrs = libx::get_window_attributes(self.context, event.window);
        println!("{} attr {} {}", event.window, attrs.width, attrs.height);
        // get window property
        let n = libx::get_text_property(self.context, event.window, xlib::XA_WM_NAME);
        match n {
            Some(s) => {debug!("create window {} for {}", event.window, s);}
            None => {}
        }

        // let atoms = libx::get_wm_protocols(self.context, event.window);
        // for a in atoms.iter() {
        //     println!("atom {}", a);
        //     let name = libx::get_atom_name(self.context, *a);
        //     match name {
        //         Some(n) => println!("name {}", n),
        //         None => println!("name {}", a),
        //     };
        // }
    }

    pub fn handle_destroy(&mut self, event: &xlib::XDestroyWindowEvent) {
        self.workspaces.remove_window(event.window);
        if self.workspaces.get_focus().is_none() {
            self.workspaces.set_focus(self.context.root);
        }
    }

    pub fn handle_map_request(&mut self, event: &xlib::XMapRequestEvent) {

        // add app top-level window to workspace
        // let window = Window::new(self.context, event.window);
        let manage = Workspaces::can_manage(self.context, event.window);

        if manage {
            debug!("top level window");
            let mut container = Container::from_id(self.context, event.window);
            container.map();
            container.focus();
            // change attributes before display
            let mask = 0x420010;
            let mask = xlib::EnterWindowMask | xlib::PropertyChangeMask;
            libx::select_input(self.context, container.id, mask);

            if self.config.titlebar_height > 0 {
                container.titlebar_height = self.config.titlebar_height as usize;
            }
            self.workspaces.add_window(container, None);
        }
        else {
            libx::map_window(self.context, event.window);
        }
    }

    pub fn handle_client_message(&mut self, event: &xlib::XClientMessageEvent) {
        println!("message type {}", event.message_type);
        let s = libx::get_atom_name(self.context, event.message_type);
        match s {
            Some(v) => println!("{}", &v),
            None => {}
        }

        match event.format {
            8 => {
                for i in 0..20 {
                    println!("{}", event.data.get_byte(i));
                }
            }
            16 => {
                for i in 0..10 {
                    println!("{}", event.data.get_short(i))
                }
            }
            32 => {
                for i in 0..5 {
                    let a = event.data.get_long(i);
                    if a != 0{
                        let s = libx::get_atom_name(self.context, a as xlib::Atom);
                        match s {
                            Some(v) => println!("{}", v),
                            None => {}
                        }
                    }
                }
            }
            _ => {}
        }
    }

    pub fn handle_button_motion(&mut self, event: &xlib::XMotionEvent) {
        let (window, _) = libx::get_input_focus(self.context);
        if window != event.window {
            self.workspaces.set_focus(event.window);
        }
    }

    pub fn handle_key_release(&mut self, event: &xlib::XKeyEvent) {
        if event.state > 0 {
            let sym = libx::lookup_keysym(*event, 0);
            let b = handler::KeyBind {
                key: sym,
                mask: event.state,
            };
            debug!("key {} {}", event.state, sym);

            match self.config.bindsyms.get_mut(&b) {
                Some(handler) => {
                    handler.handle(&mut self.workspaces, self.context);
                }
                None => {
                    println!("no bind");
                }
            }
        }
    }

    pub fn handle_property(&mut self, event: &xlib::XPropertyEvent) {
        let usertime = libx::get_atom(self.context, "_NET_WM_USER_TIME");
        match event.atom {
            usertime => {
                debug!("_NET_WM_USER_TIME");
                // let window = Window::new(self.context, event.window);
                self.workspaces.set_focus(event.window);
            }
        }
    }

    pub fn handle_configure_request(&mut self, event: &xlib::XConfigureRequestEvent) {
        let mut change = xlib::XWindowChanges {
            x: event.x,
            y: event.y,
            width: event.width,
            height: event.height,
            border_width: event.border_width,
            sibling: event.above,
            stack_mode: event.detail
        };
        debug!("config x: {}, y: {}, width: {}, height: {}",
               change.x, change.y, change.width, change.height);
        libx::configure_window(self.context, event.window, event.value_mask as u32, change);
    }

    pub fn handle_focus_in(&mut self, event: &xlib::XFocusChangeEvent) {
        self.workspaces.set_focus(event.window);
      }

    pub fn handle_enter(&mut self, event: &xlib::XCrossingEvent){
        if event.focus == 0 {
            self.workspaces.set_focus(event.window);
        }
    }

    pub fn handle(&mut self, e: xlib::XEvent) {
        let t = e.get_type();
        match t {
            xlib::CreateNotify => {
                let event: xlib::XCreateWindowEvent = From::from(e);
                debug!("create notify {}", event.window);
                self.handle_create(&event);
            }
            xlib::DestroyNotify => {
                let event: xlib::XDestroyWindowEvent = From::from(e);
                debug!("destroy notify {}", event.window);
                self.handle_destroy(&event);
            }
            xlib::MapNotify => {
                let event: xlib::XMapEvent = From::from(e);
                debug!("map notify {}", event.window);
            }
            xlib::UnmapNotify => {
                let event: xlib::XUnmapEvent = From::from(e);
                debug!("unmap notify {}", event.window);
            }
            xlib::MapRequest => {
                let event: xlib::XMapRequestEvent = From::from(e);
                debug!("map request {}", event.window);
                self.handle_map_request(&event);
            }
            xlib::ClientMessage => {
                debug!("client message");
                // let event = cast_event::<xlib::XClientMessageEvent>(&e);
                let event: xlib::XClientMessageEvent = From::from(e);
                self.handle_client_message(&event);
            }
            xlib::KeyRelease => {
                debug!("key release");
                let mut event: xlib::XKeyEvent = From::from(e);
                self.handle_key_release(&mut event);
            }
            xlib::MotionNotify => {
                let mut event: xlib::XMotionEvent = From::from(e);
                debug!("button motion {}", event.window);
                self.handle_button_motion(&event);
            }
            xlib::ButtonRelease => {
                let mut event: xlib::XButtonEvent = From::from(e);
                debug!("button release {}", event.window);
            }
            xlib::ButtonPress => {
                let mut event: xlib::XButtonEvent = From::from(e);
                debug!("button press {}", event.window);
            }
            xlib::ConfigureNotify => {
                debug!("configure notify");
            }
            xlib::ConfigureRequest =>{
                let mut event: xlib::XConfigureRequestEvent = From::from(e);
                debug!("configure request {}", event.window);
                self.handle_configure_request(&event);
            }
            xlib::FocusIn => {
                let mut event: xlib::XFocusChangeEvent = From::from(e);
                debug!("focus in {}", event.window);
                self.handle_focus_in(&event);

            }
            xlib::FocusOut => {
                let mut event: xlib::XFocusChangeEvent = From::from(e);
                debug!("focus out {}", event.window);
            }
            xlib::EnterNotify => {
                let mut event: xlib::XCrossingEvent = From::from(e);
                debug!("enter window {}", event.window);
                self.handle_enter(&event);
            }
            xlib::PropertyNotify => {
                let mut event: xlib::XPropertyEvent = From::from(e);
                debug!("property notify {}", event.window);
                self.handle_property(&event);
            }
            _ => {
                debug!("unhandled event {}", t);
            }
        }
    }
    pub fn run(&mut self) {
        loop {
            //handle events here
            let mut e = libx::next_event(self.context);
            self.handle(e);
        }
    }

    pub fn init(&mut self) {
        let mask = 0x1A0034;
        let mask = xlib::SubstructureRedirectMask | xlib::SubstructureNotifyMask;

        unsafe{
            // xlib::XSetErrorHandler(Some(error_handler));
        }
        let left_ptr: u32 = 68;
        libx::define_cursor(self.context, self.context.root, left_ptr);

        libx::ungrab_button(self.context, 0, 0x8000, self.context.root);
        libx::select_input(self.context, self.context.root,
                           mask);

        for bind in self.config.bindsyms.keys() {
            let code = libx::keysym_to_keycode(self.context, bind.key);
            libx::grab_key(self.context, code, bind.mask, self.context.root);
        }
        libx::sync(self.context, 0);

        self.init_workspaces();
    }

    fn init_workspaces(&mut self) {
        self.workspaces.create('1');
        self.workspaces.get('1').unwrap().visible = true;
        self.workspaces.switch_current('1', self.context);
    }
}
<|endoftext|>


<commit_before>//! Tests for the join code.

use Configuration;
use join::*;
use rand::{Rng, SeedableRng, XorShiftRng};
use thread_pool::*;
use unwind;

fn quick_sort<T: PartialOrd + Send>(v: &mut [T]) {
    if v.len() <= 1 {
        return;
    }

    let mid = partition(v);
    let (lo, hi) = v.split_at_mut(mid);
    join(|| quick_sort(lo), || quick_sort(hi));
}

fn partition<T: PartialOrd + Send>(v: &mut [T]) -> usize {
    let pivot = v.len() - 1;
    let mut i = 0;
    for j in 0..pivot {
        if v[j] <= v[pivot] {
            v.swap(i, j);
            i += 1;
        }
    }
    v.swap(i, pivot);
    i
}

#[test]
fn sort() {
    let mut rng = XorShiftRng::from_seed([0, 1, 2, 3]);
    let mut data: Vec<_> = (0..6 * 1024).map(|_| rng.next_u32()).collect();
    let mut sorted_data = data.clone();
    sorted_data.sort();
    quick_sort(&mut data);
    assert_eq!(data, sorted_data);
}

#[test]
fn sort_in_pool() {
    let mut rng = XorShiftRng::from_seed([0, 1, 2, 3]);
    let mut data: Vec<_> = (0..12 * 1024).map(|_| rng.next_u32()).collect();

    let pool = ThreadPool::new(Configuration::new()).unwrap();
    let mut sorted_data = data.clone();
    sorted_data.sort();
    pool.install(|| quick_sort(&mut data));
    assert_eq!(data, sorted_data);
}

#[test]
#[should_panic(expected = "Hello, world!")]
fn panic_propagate_a() {
    join(|| panic!("Hello, world!"), || ());
}

#[test]
#[should_panic(expected = "Hello, world!")]
fn panic_propagate_b() {
    join(|| (), || panic!("Hello, world!"));
}

#[test]
#[should_panic(expected = "Hello, world!")]
fn panic_propagate_both() {
    join(|| panic!("Hello, world!"), || panic!("Goodbye, world!"));
}

#[test]
fn panic_b_still_executes() {
    let mut x = false;
    match unwind::halt_unwinding(|| join(|| panic!("Hello, world!"), || x = true)) {
        Ok(_) => panic!("failed to propagate panic from closure A,"),
        Err(_) => assert!(x, "closure b failed to execute"),
    }
}

#[test]
fn join_context_both() {
    // If we're not in a pool, both should be marked stolen as they're injected.
    let (a, b) = join_context(|a| a, |b| b);
    assert!(a.migrated());
    assert!(b.migrated());
}

#[test]
fn join_context_neither() {
    // If we're already in a 1-thread pool, neither job should be stolen.
    let pool = ThreadPool::new(Configuration::new().num_threads(1)).unwrap();
    let (a, b) = pool.install(|| join_context(|a| a, |b| b));
    assert!(!a.migrated());
    assert!(!b.migrated());
}

#[test]
fn join_context_second() {
    use std::sync::Barrier;

    // If we're already in a 2-thread pool, the second job should be stolen.
    let barrier = Barrier::new(2);
    let pool = ThreadPool::new(Configuration::new().num_threads(2)).unwrap();
    let (a, b) = pool.install(|| join_context(|a| { barrier.wait(); a },
                                              |b| { barrier.wait(); b }));
    assert!(!a.migrated());
    assert!(b.migrated());
}
<commit_msg>Fix the `join_context` tests for `FnContext: !Send`<commit_after>//! Tests for the join code.

use Configuration;
use join::*;
use rand::{Rng, SeedableRng, XorShiftRng};
use thread_pool::*;
use unwind;

fn quick_sort<T: PartialOrd + Send>(v: &mut [T]) {
    if v.len() <= 1 {
        return;
    }

    let mid = partition(v);
    let (lo, hi) = v.split_at_mut(mid);
    join(|| quick_sort(lo), || quick_sort(hi));
}

fn partition<T: PartialOrd + Send>(v: &mut [T]) -> usize {
    let pivot = v.len() - 1;
    let mut i = 0;
    for j in 0..pivot {
        if v[j] <= v[pivot] {
            v.swap(i, j);
            i += 1;
        }
    }
    v.swap(i, pivot);
    i
}

#[test]
fn sort() {
    let mut rng = XorShiftRng::from_seed([0, 1, 2, 3]);
    let mut data: Vec<_> = (0..6 * 1024).map(|_| rng.next_u32()).collect();
    let mut sorted_data = data.clone();
    sorted_data.sort();
    quick_sort(&mut data);
    assert_eq!(data, sorted_data);
}

#[test]
fn sort_in_pool() {
    let mut rng = XorShiftRng::from_seed([0, 1, 2, 3]);
    let mut data: Vec<_> = (0..12 * 1024).map(|_| rng.next_u32()).collect();

    let pool = ThreadPool::new(Configuration::new()).unwrap();
    let mut sorted_data = data.clone();
    sorted_data.sort();
    pool.install(|| quick_sort(&mut data));
    assert_eq!(data, sorted_data);
}

#[test]
#[should_panic(expected = "Hello, world!")]
fn panic_propagate_a() {
    join(|| panic!("Hello, world!"), || ());
}

#[test]
#[should_panic(expected = "Hello, world!")]
fn panic_propagate_b() {
    join(|| (), || panic!("Hello, world!"));
}

#[test]
#[should_panic(expected = "Hello, world!")]
fn panic_propagate_both() {
    join(|| panic!("Hello, world!"), || panic!("Goodbye, world!"));
}

#[test]
fn panic_b_still_executes() {
    let mut x = false;
    match unwind::halt_unwinding(|| join(|| panic!("Hello, world!"), || x = true)) {
        Ok(_) => panic!("failed to propagate panic from closure A,"),
        Err(_) => assert!(x, "closure b failed to execute"),
    }
}

#[test]
fn join_context_both() {
    // If we're not in a pool, both should be marked stolen as they're injected.
    let (a_migrated, b_migrated) = join_context(|a| a.migrated(), |b| b.migrated());
    assert!(a_migrated);
    assert!(b_migrated);
}

#[test]
fn join_context_neither() {
    // If we're already in a 1-thread pool, neither job should be stolen.
    let pool = ThreadPool::new(Configuration::new().num_threads(1)).unwrap();
    let (a_migrated, b_migrated) = pool.install(|| {
        join_context(|a| a.migrated(), |b| b.migrated())
    });
    assert!(!a_migrated);
    assert!(!b_migrated);
}

#[test]
fn join_context_second() {
    use std::sync::Barrier;

    // If we're already in a 2-thread pool, the second job should be stolen.
    let barrier = Barrier::new(2);
    let pool = ThreadPool::new(Configuration::new().num_threads(2)).unwrap();
    let (a_migrated, b_migrated) = pool.install(|| {
        join_context(|a| { barrier.wait(); a.migrated() },
                     |b| { barrier.wait(); b.migrated() })
    });
    assert!(!a_migrated);
    assert!(b_migrated);
}
<|endoftext|>


<commit_before>//! Test map generators by displaying generated text maps in console.

extern crate calx;
extern crate rand;
extern crate world;

use calx::Prefab;
use rand::Rng;
use std::collections::HashMap;
use std::fmt::Write;
use std::iter::FromIterator;
use std::str;
use world::{Room, Sector};
use world::mapgen::{self, MapGen, Point2D, Vault, VaultCell};

struct TestMap {
    terrain: HashMap<Point2D, char>,
}

impl TestMap {
    pub fn new() -> TestMap {
        let mut terrain = HashMap::new();

        let sector = Sector::new(0, 0, 0);
        let sector_origin = sector.origin();
        let mapgen_origin = Point2D::zero();

        terrain.extend(
            sector
                .iter()
                .map(|loc| mapgen_origin + sector_origin.v2_at(loc).unwrap())
                .map(|p| (p, '*')),
        );

        TestMap { terrain }
    }
}

impl mapgen::Dungeon for TestMap {
    type Vault = Room;

    /// Return a random prefab room.
    fn sample_vault<R: Rng>(&mut self, rng: &mut R) -> Self::Vault { rng.gen() }

    /// Add a large open continuous region to dungeon.
    fn dig_chamber<I: IntoIterator<Item = Point2D>>(&mut self, area: I) {
        for pos in area {
            self.terrain.insert(pos, '.');
        }
    }

    /// Add a narrow corridor to dungeon.
    fn dig_corridor<I: IntoIterator<Item = Point2D>>(&mut self, path: I) {
        for pos in path {
            self.terrain.insert(pos, '▒');
        }
    }

    fn place_vault(&mut self, vault: &Self::Vault, pos: Point2D) {
        let points: Vec<(Point2D, VaultCell)> = vault.get_shape();
        for &(p, c) in &points {
            let p = p + pos.to_vector();
            if !self.terrain.contains_key(&p) {
                continue;
            }
            let c = match c {
                VaultCell::Interior => '.',
                _ => '#',
            };
            self.terrain.insert(p, c);
        }
    }

    fn add_door(&mut self, pos: Point2D) { self.terrain.insert(pos, '|'); }

    fn add_up_stairs(&mut self, pos: Point2D) { self.terrain.insert(pos, '<'); }

    fn add_down_stairs(&mut self, pos: Point2D) { self.terrain.insert(pos, '>'); }
}

fn main() {
    let mut map = TestMap::new();

    let domain: Vec<Point2D> = map.terrain.keys().cloned().collect();
    mapgen::RoomsAndCorridors.dig(&mut rand::thread_rng(), &mut map, domain);

    let map_text = String::from(Prefab::from_iter(
        map.terrain.iter().map(|(p, t)| (p.to_vector(), *t)),
    ));

    let mut new_text = String::new();

    for line in map_text.lines() {
        let mut line = line.to_string();
        let mut bytes: Vec<u8> = line.bytes().collect();
        for i in 1..(bytes.len() - 1) {
            for &(a, b, c) in &[
                ('*', '*', '*'),
                ('#', '#', '#'),
                ('*', '#', '*'),
                ('#', '*', '*'),
                ('|', '#', '#'),
                ('#', '|', '#'),
            ]
            {
                if bytes[i] == ' ' as u8 && bytes[i - 1] == a as u8 && bytes[i + 1] == b as u8 {
                    bytes[i] = c as u8;
                }
            }
        }
        let _ = writeln!(&mut new_text, "{}", str::from_utf8(&bytes).unwrap());
    }

    println!("{}", new_text);
}
<commit_msg>Rustfmt<commit_after>//! Test map generators by displaying generated text maps in console.

extern crate calx;
extern crate rand;
extern crate world;

use calx::Prefab;
use rand::Rng;
use std::collections::HashMap;
use std::fmt::Write;
use std::iter::FromIterator;
use std::str;
use world::{Room, Sector};
use world::mapgen::{self, MapGen, Point2D, Vault, VaultCell};

struct TestMap {
    terrain: HashMap<Point2D, char>,
}

impl TestMap {
    pub fn new() -> TestMap {
        let mut terrain = HashMap::new();

        let sector = Sector::new(0, 0, 0);
        let sector_origin = sector.origin();
        let mapgen_origin = Point2D::zero();

        terrain.extend(
            sector
                .iter()
                .map(|loc| mapgen_origin + sector_origin.v2_at(loc).unwrap())
                .map(|p| (p, '*')),
        );

        TestMap { terrain }
    }
}

impl mapgen::Dungeon for TestMap {
    type Vault = Room;

    /// Return a random prefab room.
    fn sample_vault<R: Rng>(&mut self, rng: &mut R) -> Self::Vault { rng.gen() }

    /// Add a large open continuous region to dungeon.
    fn dig_chamber<I: IntoIterator<Item = Point2D>>(&mut self, area: I) {
        for pos in area {
            self.terrain.insert(pos, '.');
        }
    }

    /// Add a narrow corridor to dungeon.
    fn dig_corridor<I: IntoIterator<Item = Point2D>>(&mut self, path: I) {
        for pos in path {
            self.terrain.insert(pos, '▒');
        }
    }

    fn place_vault(&mut self, vault: &Self::Vault, pos: Point2D) {
        let points: Vec<(Point2D, VaultCell)> = vault.get_shape();
        for &(p, c) in &points {
            let p = p + pos.to_vector();
            if !self.terrain.contains_key(&p) {
                continue;
            }
            let c = match c {
                VaultCell::Interior => '.',
                _ => '#',
            };
            self.terrain.insert(p, c);
        }
    }

    fn add_door(&mut self, pos: Point2D) { self.terrain.insert(pos, '|'); }

    fn add_up_stairs(&mut self, pos: Point2D) { self.terrain.insert(pos, '<'); }

    fn add_down_stairs(&mut self, pos: Point2D) { self.terrain.insert(pos, '>'); }
}

fn main() {
    let mut map = TestMap::new();

    let domain: Vec<Point2D> = map.terrain.keys().cloned().collect();
    mapgen::RoomsAndCorridors.dig(&mut rand::thread_rng(), &mut map, domain);

    let map_text = String::from(Prefab::from_iter(
        map.terrain.iter().map(|(p, t)| (p.to_vector(), *t)),
    ));

    let mut new_text = String::new();

    for line in map_text.lines() {
        let mut line = line.to_string();
        let mut bytes: Vec<u8> = line.bytes().collect();
        for i in 1..(bytes.len() - 1) {
            for &(a, b, c) in &[
                ('*', '*', '*'),
                ('#', '#', '#'),
                ('*', '#', '*'),
                ('#', '*', '*'),
                ('|', '#', '#'),
                ('#', '|', '#'),
            ] {
                if bytes[i] == ' ' as u8 && bytes[i - 1] == a as u8 && bytes[i + 1] == b as u8 {
                    bytes[i] = c as u8;
                }
            }
        }
        let _ = writeln!(&mut new_text, "{}", str::from_utf8(&bytes).unwrap());
    }

    println!("{}", new_text);
}
<|endoftext|>


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

#![crate_name = "rustc_borrowck"]
#![experimental]
#![crate_type = "dylib"]
#![crate_type = "rlib"]
#![doc(html_logo_url = "http://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png",
      html_favicon_url = "http://www.rust-lang.org/favicon.ico",
      html_root_url = "http://doc.rust-lang.org/nightly/")]

#![feature(default_type_params, globs, if_let, import_shadowing, macro_rules, phase, quote)]
#![feature(slicing_syntax, tuple_indexing, unsafe_destructor)]
#![feature(rustc_diagnostic_macros)]
#![allow(non_camel_case_types)]

#[phase(plugin, link)] extern crate log;
#[phase(plugin, link)] extern crate syntax;

// for "clarity", rename the graphviz crate to dot; graphviz within `borrowck`
// refers to the borrowck-specific graphviz adapter traits.
extern crate "graphviz" as dot;
extern crate rustc;

pub use borrowck::check_crate;
pub use borrowck::build_borrowck_dataflow_data_for_fn;
pub use borrowck::FnPartsWithCFG;

mod borrowck;

pub mod graphviz;

<commit_msg>librustc_borrowck: add `#![feature(unboxed_closures)]`<commit_after>// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

#![crate_name = "rustc_borrowck"]
#![experimental]
#![crate_type = "dylib"]
#![crate_type = "rlib"]
#![doc(html_logo_url = "http://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png",
      html_favicon_url = "http://www.rust-lang.org/favicon.ico",
      html_root_url = "http://doc.rust-lang.org/nightly/")]

#![feature(default_type_params, globs, if_let, import_shadowing, macro_rules, phase, quote)]
#![feature(slicing_syntax, tuple_indexing, unsafe_destructor)]
#![feature(rustc_diagnostic_macros)]
#![feature(unboxed_closures)]
#![allow(non_camel_case_types)]

#[phase(plugin, link)] extern crate log;
#[phase(plugin, link)] extern crate syntax;

// for "clarity", rename the graphviz crate to dot; graphviz within `borrowck`
// refers to the borrowck-specific graphviz adapter traits.
extern crate "graphviz" as dot;
extern crate rustc;

pub use borrowck::check_crate;
pub use borrowck::build_borrowck_dataflow_data_for_fn;
pub use borrowck::FnPartsWithCFG;

mod borrowck;

pub mod graphviz;

<|endoftext|>


<commit_before>
/// A priority queue implemented with a binary heap
use core::cmp::Ord;
use ptr::addr_of;

#[abi = "rust-intrinsic"]
extern "C" mod rusti {
    fn move_val_init<T>(dst: &mut T, -src: T);
}

pub struct PriorityQueue <T: Ord>{
    priv data: ~[T],
}

impl <T: Ord> PriorityQueue<T> {
    /// Returns the greatest item in the queue - fails if empty
    pure fn top(&self) -> &self/T { &self.data[0] }

    /// Returns the greatest item in the queue - None if empty
    pure fn maybe_top(&self) -> Option<&self/T> {
        if self.is_empty() { None } else { Some(self.top()) }
    }

    /// Returns the length of the queue
    pure fn len(&self) -> uint { self.data.len() }

    /// Returns true if a queue contains no elements
    pure fn is_empty(&self) -> bool { self.data.is_empty() }

    /// Returns true if a queue contains some elements
    pure fn is_not_empty(&self) -> bool { self.data.is_not_empty() }

    /// Returns the number of elements the queue can hold without reallocating
    pure fn capacity(&self) -> uint { vec::capacity(&self.data) }

    fn reserve(&mut self, n: uint) { vec::reserve(&mut self.data, n) }

    fn reserve_at_least(&mut self, n: uint) {
        vec::reserve_at_least(&mut self.data, n)
    }

    /// Drop all items from the queue
    fn clear(&mut self) { self.data.truncate(0) }

    /// Pop the greatest item from the queue - fails if empty
    fn pop(&mut self) -> T {
        let mut item = self.data.pop();
        if self.is_not_empty() { item <-> self.data[0]; self.siftdown(0); }
        item
    }

    /// Pop the greatest item from the queue - None if empty
    fn maybe_pop(&mut self) -> Option<T> {
        if self.is_empty() { None } else { Some(self.pop()) }
    }

    /// Push an item onto the queue
    fn push(&mut self, item: T) {
        self.data.push(item);
        self.siftup(0, self.len() - 1);
    }

    /// Optimized version of a push followed by a pop
    fn push_pop(&mut self, item: T) -> T {
        let mut item = item;
        if self.is_not_empty() && self.data[0] > item {
            item <-> self.data[0];
            self.siftdown(0);
        }
        item
    }

    /// Optimized version of a pop followed by a push - fails if empty
    fn replace(&mut self, item: T) -> T {
        let mut item = item;
        item <-> self.data[0];
        self.siftdown(0);
        item
    }

    /// Consume the PriorityQueue and return the underlying vector
    #[cfg(stage0)]
    pure fn to_vec(self) -> ~[T] { fail }
    #[cfg(stage1)]
    #[cfg(stage2)]
    #[cfg(stage3)]
    pure fn to_vec(self) -> ~[T] { let PriorityQueue{data: v} = self; v }

    /// Consume the PriorityQueue and return a vector in sorted (ascending) order
    #[cfg(stage0)]
    pure fn to_sorted_vec(self) -> ~[T] { fail }
    #[cfg(stage1)]
    #[cfg(stage2)]
    #[cfg(stage3)]
    pure fn to_sorted_vec(self) -> ~[T] {
        let mut q = self;
        let mut end = q.len();
        while end > 1 {
            end -= 1;
            q.data[end] <-> q.data[0];
            unsafe { q.siftdown_range(0, end) } // purity-checking workaround
        }
        q.to_vec()
    }

    /// Create a PriorityQueue from a vector (heapify)
    static pub pure fn from_vec(xs: ~[T]) -> PriorityQueue<T> {
        let mut q = PriorityQueue{data: xs,};
        let mut n = q.len() / 2;
        while n > 0 {
            n -= 1;
            unsafe { q.siftdown(n) }; // purity-checking workaround
        }
        q
    }

    // The implementations of siftup and siftdown use unsafe blocks in order to
    // move an element out of the vector (leaving behind a junk element), shift
    // along the others and move it back into the vector over the junk element.
    // This reduces the constant factor compared to using swaps, which involves
    // twice as many moves.

    priv fn siftup(&mut self, start: uint, pos: uint) unsafe {
        let mut pos = pos;
        let new = move *addr_of(&self.data[pos]);

        while pos > start {
            let parent = (pos - 1) >> 1;
            if new > self.data[parent] {
                rusti::move_val_init(&mut self.data[pos],
                                     move *addr_of(&self.data[parent]));
                pos = parent;
                loop
            }
            break
        }
        rusti::move_val_init(&mut self.data[pos], move new);
    }

    priv fn siftdown_range(&mut self, pos: uint, end: uint) unsafe {
        let mut pos = pos;
        let start = pos;
        let new = move *addr_of(&self.data[pos]);

        let mut child = 2 * pos + 1;
        while child < end {
            let right = child + 1;
            if right < end && !(self.data[child] > self.data[right]) {
                child = right;
            }
            rusti::move_val_init(&mut self.data[pos],
                                 move *addr_of(&self.data[child]));
            pos = child;
            child = 2 * pos + 1;
        }
        rusti::move_val_init(&mut self.data[pos], move new);
        self.siftup(start, pos);
    }

    priv fn siftdown(&mut self, pos: uint) {
        self.siftdown_range(pos, self.len());
    }
}

#[cfg(test)]
mod tests {
    use sort::merge_sort;
    use core::cmp::le;
    use priority_queue::PriorityQueue::from_vec;

    #[test]
    fn test_top_and_pop() {
        let data = ~[2, 4, 6, 2, 1, 8, 10, 3, 5, 7, 0, 9, 1];
        let mut sorted = merge_sort(data, le);
        let mut heap = from_vec(data);
        while heap.is_not_empty() {
            assert *heap.top() == sorted.last();
            assert heap.pop() == sorted.pop();
        }
    }

    #[test]
    fn test_push() {
        let mut heap = from_vec(~[2, 4, 9]);
        assert heap.len() == 3;
        assert *heap.top() == 9;
        heap.push(11);
        assert heap.len() == 4;
        assert *heap.top() == 11;
        heap.push(5);
        assert heap.len() == 5;
        assert *heap.top() == 11;
        heap.push(27);
        assert heap.len() == 6;
        assert *heap.top() == 27;
        heap.push(3);
        assert heap.len() == 7;
        assert *heap.top() == 27;
        heap.push(103);
        assert heap.len() == 8;
        assert *heap.top() == 103;
    }

    #[test]
    fn test_push_pop() {
        let mut heap = from_vec(~[5, 5, 2, 1, 3]);
        assert heap.len() == 5;
        assert heap.push_pop(6) == 6;
        assert heap.len() == 5;
        assert heap.push_pop(0) == 5;
        assert heap.len() == 5;
        assert heap.push_pop(4) == 5;
        assert heap.len() == 5;
        assert heap.push_pop(1) == 4;
        assert heap.len() == 5;
    }

    #[test]
    fn test_replace() {
        let mut heap = from_vec(~[5, 5, 2, 1, 3]);
        assert heap.len() == 5;
        assert heap.replace(6) == 5;
        assert heap.len() == 5;
        assert heap.replace(0) == 6;
        assert heap.len() == 5;
        assert heap.replace(4) == 5;
        assert heap.len() == 5;
        assert heap.replace(1) == 4;
        assert heap.len() == 5;
    }

    fn check_to_vec(data: ~[int]) {
        let heap = from_vec(data);
        assert merge_sort(heap.to_vec(), le) == merge_sort(data, le);
        assert heap.to_sorted_vec() == merge_sort(data, le);
    }

    #[test]
    fn test_to_vec() {
        check_to_vec(~[]);
        check_to_vec(~[5]);
        check_to_vec(~[3, 2]);
        check_to_vec(~[2, 3]);
        check_to_vec(~[5, 1, 2]);
        check_to_vec(~[1, 100, 2, 3]);
        check_to_vec(~[1, 3, 5, 7, 9, 2, 4, 6, 8, 0]);
        check_to_vec(~[2, 4, 6, 2, 1, 8, 10, 3, 5, 7, 0, 9, 1]);
        check_to_vec(~[9, 11, 9, 9, 9, 9, 11, 2, 3, 4, 11, 9, 0, 0, 0, 0]);
        check_to_vec(~[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]);
        check_to_vec(~[10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0]);
        check_to_vec(~[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 0, 0, 1, 2]);
        check_to_vec(~[5, 4, 3, 2, 1, 5, 4, 3, 2, 1, 5, 4, 3, 2, 1]);
    }

    #[test]
    #[should_fail]
    #[ignore(cfg(windows))]
    fn test_empty_pop() { let mut heap = from_vec::<int>(~[]); heap.pop(); }

    #[test]
    fn test_empty_maybe_pop() {
        let mut heap = from_vec::<int>(~[]);
        assert heap.maybe_pop().is_none();
    }

    #[test]
    #[should_fail]
    #[ignore(cfg(windows))]
    fn test_empty_top() { let empty = from_vec::<int>(~[]); empty.top(); }

    #[test]
    fn test_empty_maybe_top() {
        let empty = from_vec::<int>(~[]);
        assert empty.maybe_top().is_none();
    }

    #[test]
    #[should_fail]
    #[ignore(cfg(windows))]
    fn test_empty_replace() {
        let mut heap = from_vec::<int>(~[]);
        heap.replace(5);
    }
}
<commit_msg>Add priority_queue test for unique pointers<commit_after>
/// A priority queue implemented with a binary heap
use core::cmp::Ord;
use ptr::addr_of;

#[abi = "rust-intrinsic"]
extern "C" mod rusti {
    fn move_val_init<T>(dst: &mut T, -src: T);
}

pub struct PriorityQueue <T: Ord>{
    priv data: ~[T],
}

impl <T: Ord> PriorityQueue<T> {
    /// Returns the greatest item in the queue - fails if empty
    pure fn top(&self) -> &self/T { &self.data[0] }

    /// Returns the greatest item in the queue - None if empty
    pure fn maybe_top(&self) -> Option<&self/T> {
        if self.is_empty() { None } else { Some(self.top()) }
    }

    /// Returns the length of the queue
    pure fn len(&self) -> uint { self.data.len() }

    /// Returns true if a queue contains no elements
    pure fn is_empty(&self) -> bool { self.data.is_empty() }

    /// Returns true if a queue contains some elements
    pure fn is_not_empty(&self) -> bool { self.data.is_not_empty() }

    /// Returns the number of elements the queue can hold without reallocating
    pure fn capacity(&self) -> uint { vec::capacity(&self.data) }

    fn reserve(&mut self, n: uint) { vec::reserve(&mut self.data, n) }

    fn reserve_at_least(&mut self, n: uint) {
        vec::reserve_at_least(&mut self.data, n)
    }

    /// Drop all items from the queue
    fn clear(&mut self) { self.data.truncate(0) }

    /// Pop the greatest item from the queue - fails if empty
    fn pop(&mut self) -> T {
        let mut item = self.data.pop();
        if self.is_not_empty() { item <-> self.data[0]; self.siftdown(0); }
        item
    }

    /// Pop the greatest item from the queue - None if empty
    fn maybe_pop(&mut self) -> Option<T> {
        if self.is_empty() { None } else { Some(self.pop()) }
    }

    /// Push an item onto the queue
    fn push(&mut self, item: T) {
        self.data.push(item);
        self.siftup(0, self.len() - 1);
    }

    /// Optimized version of a push followed by a pop
    fn push_pop(&mut self, item: T) -> T {
        let mut item = item;
        if self.is_not_empty() && self.data[0] > item {
            item <-> self.data[0];
            self.siftdown(0);
        }
        item
    }

    /// Optimized version of a pop followed by a push - fails if empty
    fn replace(&mut self, item: T) -> T {
        let mut item = item;
        item <-> self.data[0];
        self.siftdown(0);
        item
    }

    /// Consume the PriorityQueue and return the underlying vector
    #[cfg(stage0)]
    pure fn to_vec(self) -> ~[T] { fail }
    #[cfg(stage1)]
    #[cfg(stage2)]
    #[cfg(stage3)]
    pure fn to_vec(self) -> ~[T] { let PriorityQueue{data: v} = self; v }

    /// Consume the PriorityQueue and return a vector in sorted (ascending) order
    #[cfg(stage0)]
    pure fn to_sorted_vec(self) -> ~[T] { fail }
    #[cfg(stage1)]
    #[cfg(stage2)]
    #[cfg(stage3)]
    pure fn to_sorted_vec(self) -> ~[T] {
        let mut q = self;
        let mut end = q.len();
        while end > 1 {
            end -= 1;
            q.data[end] <-> q.data[0];
            unsafe { q.siftdown_range(0, end) } // purity-checking workaround
        }
        q.to_vec()
    }

    /// Create a PriorityQueue from a vector (heapify)
    static pub pure fn from_vec(xs: ~[T]) -> PriorityQueue<T> {
        let mut q = PriorityQueue{data: xs,};
        let mut n = q.len() / 2;
        while n > 0 {
            n -= 1;
            unsafe { q.siftdown(n) }; // purity-checking workaround
        }
        q
    }

    // The implementations of siftup and siftdown use unsafe blocks in order to
    // move an element out of the vector (leaving behind a junk element), shift
    // along the others and move it back into the vector over the junk element.
    // This reduces the constant factor compared to using swaps, which involves
    // twice as many moves.

    priv fn siftup(&mut self, start: uint, pos: uint) unsafe {
        let mut pos = pos;
        let new = move *addr_of(&self.data[pos]);

        while pos > start {
            let parent = (pos - 1) >> 1;
            if new > self.data[parent] {
                rusti::move_val_init(&mut self.data[pos],
                                     move *addr_of(&self.data[parent]));
                pos = parent;
                loop
            }
            break
        }
        rusti::move_val_init(&mut self.data[pos], move new);
    }

    priv fn siftdown_range(&mut self, pos: uint, end: uint) unsafe {
        let mut pos = pos;
        let start = pos;
        let new = move *addr_of(&self.data[pos]);

        let mut child = 2 * pos + 1;
        while child < end {
            let right = child + 1;
            if right < end && !(self.data[child] > self.data[right]) {
                child = right;
            }
            rusti::move_val_init(&mut self.data[pos],
                                 move *addr_of(&self.data[child]));
            pos = child;
            child = 2 * pos + 1;
        }
        rusti::move_val_init(&mut self.data[pos], move new);
        self.siftup(start, pos);
    }

    priv fn siftdown(&mut self, pos: uint) {
        self.siftdown_range(pos, self.len());
    }
}

#[cfg(test)]
mod tests {
    use sort::merge_sort;
    use core::cmp::le;
    use priority_queue::PriorityQueue::from_vec;

    #[test]
    fn test_top_and_pop() {
        let data = ~[2, 4, 6, 2, 1, 8, 10, 3, 5, 7, 0, 9, 1];
        let mut sorted = merge_sort(data, le);
        let mut heap = from_vec(data);
        while heap.is_not_empty() {
            assert *heap.top() == sorted.last();
            assert heap.pop() == sorted.pop();
        }
    }

    #[test]
    fn test_push() {
        let mut heap = from_vec(~[2, 4, 9]);
        assert heap.len() == 3;
        assert *heap.top() == 9;
        heap.push(11);
        assert heap.len() == 4;
        assert *heap.top() == 11;
        heap.push(5);
        assert heap.len() == 5;
        assert *heap.top() == 11;
        heap.push(27);
        assert heap.len() == 6;
        assert *heap.top() == 27;
        heap.push(3);
        assert heap.len() == 7;
        assert *heap.top() == 27;
        heap.push(103);
        assert heap.len() == 8;
        assert *heap.top() == 103;
    }

    #[test]
    fn test_push_unique() {
        let mut heap = from_vec(~[~2, ~4, ~9]);
        assert heap.len() == 3;
        assert *heap.top() == ~9;
        heap.push(~11);
        assert heap.len() == 4;
        assert *heap.top() == ~11;
        heap.push(~5);
        assert heap.len() == 5;
        assert *heap.top() == ~11;
        heap.push(~27);
        assert heap.len() == 6;
        assert *heap.top() == ~27;
        heap.push(~3);
        assert heap.len() == 7;
        assert *heap.top() == ~27;
        heap.push(~103);
        assert heap.len() == 8;
        assert *heap.top() == ~103;
    }

    #[test]
    fn test_push_pop() {
        let mut heap = from_vec(~[5, 5, 2, 1, 3]);
        assert heap.len() == 5;
        assert heap.push_pop(6) == 6;
        assert heap.len() == 5;
        assert heap.push_pop(0) == 5;
        assert heap.len() == 5;
        assert heap.push_pop(4) == 5;
        assert heap.len() == 5;
        assert heap.push_pop(1) == 4;
        assert heap.len() == 5;
    }

    #[test]
    fn test_replace() {
        let mut heap = from_vec(~[5, 5, 2, 1, 3]);
        assert heap.len() == 5;
        assert heap.replace(6) == 5;
        assert heap.len() == 5;
        assert heap.replace(0) == 6;
        assert heap.len() == 5;
        assert heap.replace(4) == 5;
        assert heap.len() == 5;
        assert heap.replace(1) == 4;
        assert heap.len() == 5;
    }

    fn check_to_vec(data: ~[int]) {
        let heap = from_vec(data);
        assert merge_sort(heap.to_vec(), le) == merge_sort(data, le);
        assert heap.to_sorted_vec() == merge_sort(data, le);
    }

    #[test]
    fn test_to_vec() {
        check_to_vec(~[]);
        check_to_vec(~[5]);
        check_to_vec(~[3, 2]);
        check_to_vec(~[2, 3]);
        check_to_vec(~[5, 1, 2]);
        check_to_vec(~[1, 100, 2, 3]);
        check_to_vec(~[1, 3, 5, 7, 9, 2, 4, 6, 8, 0]);
        check_to_vec(~[2, 4, 6, 2, 1, 8, 10, 3, 5, 7, 0, 9, 1]);
        check_to_vec(~[9, 11, 9, 9, 9, 9, 11, 2, 3, 4, 11, 9, 0, 0, 0, 0]);
        check_to_vec(~[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]);
        check_to_vec(~[10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0]);
        check_to_vec(~[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 0, 0, 1, 2]);
        check_to_vec(~[5, 4, 3, 2, 1, 5, 4, 3, 2, 1, 5, 4, 3, 2, 1]);
    }

    #[test]
    #[should_fail]
    #[ignore(cfg(windows))]
    fn test_empty_pop() { let mut heap = from_vec::<int>(~[]); heap.pop(); }

    #[test]
    fn test_empty_maybe_pop() {
        let mut heap = from_vec::<int>(~[]);
        assert heap.maybe_pop().is_none();
    }

    #[test]
    #[should_fail]
    #[ignore(cfg(windows))]
    fn test_empty_top() { let empty = from_vec::<int>(~[]); empty.top(); }

    #[test]
    fn test_empty_maybe_top() {
        let empty = from_vec::<int>(~[]);
        assert empty.maybe_top().is_none();
    }

    #[test]
    #[should_fail]
    #[ignore(cfg(windows))]
    fn test_empty_replace() {
        let mut heap = from_vec::<int>(~[]);
        heap.replace(5);
    }
}
<|endoftext|>


<commit_before>use num::NonZeroUsize;
use slice;
use str;

use super::waitqueue::{
    try_lock_or_false, NotifiedTcs, SpinMutex, SpinMutexGuard, WaitQueue, WaitVariable,
};
use mem;

pub struct RWLock {
    readers: SpinMutex<WaitVariable<Option<NonZeroUsize>>>,
    writer: SpinMutex<WaitVariable<bool>>,
}

// Below is to check at compile time, that RWLock has size of 128 bytes.
#[allow(dead_code)]
unsafe fn rw_lock_size_assert(r: RWLock) {
    mem::transmute::<RWLock, [u8; 128]>(r);
}

//unsafe impl Send for RWLock {}
//unsafe impl Sync for RWLock {} // FIXME

impl RWLock {
    pub const fn new() -> RWLock {
        RWLock {
            readers: SpinMutex::new(WaitVariable::new(None)),
            writer: SpinMutex::new(WaitVariable::new(false)),
        }
    }

    #[inline]
    pub unsafe fn read(&self) {
        let mut rguard = self.readers.lock();
        let wguard = self.writer.lock();
        if *wguard.lock_var() || !wguard.queue_empty() {
            // Another thread has or is waiting for the write lock, wait
            drop(wguard);
            WaitQueue::wait(rguard);
            // Another thread has passed the lock to us
        } else {
            // No waiting writers, acquire the read lock
            *rguard.lock_var_mut() =
                NonZeroUsize::new(rguard.lock_var().map_or(0, |n| n.get()) + 1);
        }
    }

    #[inline]
    pub unsafe fn try_read(&self) -> bool {
        let mut rguard = try_lock_or_false!(self.readers);
        let wguard = try_lock_or_false!(self.writer);
        if *wguard.lock_var() || !wguard.queue_empty() {
            // Another thread has or is waiting for the write lock
            false
        } else {
            // No waiting writers, acquire the read lock
            *rguard.lock_var_mut() =
                NonZeroUsize::new(rguard.lock_var().map_or(0, |n| n.get()) + 1);
            true
        }
    }

    #[inline]
    pub unsafe fn write(&self) {
        let rguard = self.readers.lock();
        let mut wguard = self.writer.lock();
        if *wguard.lock_var() || rguard.lock_var().is_some() {
            // Another thread has the lock, wait
            drop(rguard);
            WaitQueue::wait(wguard);
            // Another thread has passed the lock to us
        } else {
            // We are just now obtaining the lock
            *wguard.lock_var_mut() = true;
        }
    }

    #[inline]
    pub unsafe fn try_write(&self) -> bool {
        let rguard = try_lock_or_false!(self.readers);
        let mut wguard = try_lock_or_false!(self.writer);
        if *wguard.lock_var() || rguard.lock_var().is_some() {
            // Another thread has the lock
            false
        } else {
            // We are just now obtaining the lock
            *wguard.lock_var_mut() = true;
            true
        }
    }

    #[inline]
    unsafe fn __read_unlock(
        &self,
        mut rguard: SpinMutexGuard<WaitVariable<Option<NonZeroUsize>>>,
        wguard: SpinMutexGuard<WaitVariable<bool>>,
    ) {
        *rguard.lock_var_mut() = NonZeroUsize::new(rguard.lock_var().unwrap().get() - 1);
        if rguard.lock_var().is_some() {
            // There are other active readers
        } else {
            if let Ok(mut wguard) = WaitQueue::notify_one(wguard) {
                // A writer was waiting, pass the lock
                *wguard.lock_var_mut() = true;
            } else {
                // No writers were waiting, the lock is released
                assert!(rguard.queue_empty());
            }
        }
    }

    #[inline]
    pub unsafe fn read_unlock(&self) {
        let rguard = self.readers.lock();
        let wguard = self.writer.lock();
        self.__read_unlock(rguard, wguard);
    }

    #[inline]
    unsafe fn __write_unlock(
        &self,
        rguard: SpinMutexGuard<WaitVariable<Option<NonZeroUsize>>>,
        wguard: SpinMutexGuard<WaitVariable<bool>>,
    ) {
        if let Err(mut wguard) = WaitQueue::notify_one(wguard) {
            // No writers waiting, release the write lock
            *wguard.lock_var_mut() = false;
            if let Ok(mut rguard) = WaitQueue::notify_all(rguard) {
                // One or more readers were waiting, pass the lock to them
                if let NotifiedTcs::All { count } = rguard.notified_tcs() {
                    *rguard.lock_var_mut() = Some(count)
                } else {
                    unreachable!() // called notify_all
                }
            } else {
                // No readers waiting, the lock is released
            }
        } else {
            // There was a thread waiting for write, just pass the lock
        }
    }

    #[inline]
    pub unsafe fn write_unlock(&self) {
        let rguard = self.readers.lock();
        let wguard = self.writer.lock();
        self.__write_unlock(rguard, wguard);
    }

    #[inline]
    unsafe fn unlock(&self) {
        let rguard = self.readers.lock();
        let wguard = self.writer.lock();
        if *wguard.lock_var() == true {
            self.__write_unlock(rguard, wguard);
        } else {
            self.__read_unlock(rguard, wguard);
        }
    }

    #[inline]
    pub unsafe fn destroy(&self) {}
}

const EINVAL: i32 = 22;

#[no_mangle]
pub unsafe extern "C" fn __rust_rwlock_rdlock(p: *mut RWLock) -> i32 {
    if p.is_null() {
        return EINVAL;
    }
    (*p).read();
    return 0;
}

#[no_mangle]
pub unsafe extern "C" fn __rust_rwlock_wrlock(p: *mut RWLock) -> i32 {
    if p.is_null() {
        return EINVAL;
    }
    (*p).write();
    return 0;
}
#[no_mangle]
pub unsafe extern "C" fn __rust_rwlock_unlock(p: *mut RWLock) -> i32 {
    if p.is_null() {
        return EINVAL;
    }
    (*p).unlock();
    return 0;
}

#[no_mangle]
pub unsafe extern "C" fn __rust_print_err(m: *mut u8, s: i32) {
    if s < 0 {
        return;
    }
    let buf = slice::from_raw_parts(m as *const u8, s as _);
    if let Ok(s) = str::from_utf8(&buf[..buf.iter().position(|&b| b == 0).unwrap_or(buf.len())]) {
        eprint!("{}", s);
    }
}

#[no_mangle]
pub unsafe extern "C" fn __rust_abort() {
    ::sys::abort_internal();
}

#[cfg(test)]
mod tests {

    use super::*;
    use core::array::FixedSizeArray;
    use mem::MaybeUninit;
    use {mem, ptr};

    // The below test verifies that the bytes of initialized RWLock are the ones
    // we use in libunwind.
    // If they change we need to update src/UnwindRustSgx.h in libunwind.
    #[test]
    fn test_c_rwlock_initializer() {
        const RWLOCK_INIT: &[u8] = &[
            0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
            0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
            0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
            0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
            0x3, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
            0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
            0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
            0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
            0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
            0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
            0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
            0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
            0x3, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
            0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
            0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
            0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
        ];

        let mut init = MaybeUninit::<RWLock>::zeroed();
        init.set(RWLock::new());
        assert_eq!(
            mem::transmute::<_, [u8; 128]>(init.into_inner()).as_slice(),
            RWLOCK_INIT
        );
    }
}
<commit_msg>Expose alloc/dealloc properly for SGX libunwind<commit_after>use alloc::{self, Layout};
use num::NonZeroUsize;
use slice;
use str;

use super::waitqueue::{
    try_lock_or_false, NotifiedTcs, SpinMutex, SpinMutexGuard, WaitQueue, WaitVariable,
};
use mem;

pub struct RWLock {
    readers: SpinMutex<WaitVariable<Option<NonZeroUsize>>>,
    writer: SpinMutex<WaitVariable<bool>>,
}

// Below is to check at compile time, that RWLock has size of 128 bytes.
#[allow(dead_code)]
unsafe fn rw_lock_size_assert(r: RWLock) {
    mem::transmute::<RWLock, [u8; 128]>(r);
}

//unsafe impl Send for RWLock {}
//unsafe impl Sync for RWLock {} // FIXME

impl RWLock {
    pub const fn new() -> RWLock {
        RWLock {
            readers: SpinMutex::new(WaitVariable::new(None)),
            writer: SpinMutex::new(WaitVariable::new(false)),
        }
    }

    #[inline]
    pub unsafe fn read(&self) {
        let mut rguard = self.readers.lock();
        let wguard = self.writer.lock();
        if *wguard.lock_var() || !wguard.queue_empty() {
            // Another thread has or is waiting for the write lock, wait
            drop(wguard);
            WaitQueue::wait(rguard);
            // Another thread has passed the lock to us
        } else {
            // No waiting writers, acquire the read lock
            *rguard.lock_var_mut() =
                NonZeroUsize::new(rguard.lock_var().map_or(0, |n| n.get()) + 1);
        }
    }

    #[inline]
    pub unsafe fn try_read(&self) -> bool {
        let mut rguard = try_lock_or_false!(self.readers);
        let wguard = try_lock_or_false!(self.writer);
        if *wguard.lock_var() || !wguard.queue_empty() {
            // Another thread has or is waiting for the write lock
            false
        } else {
            // No waiting writers, acquire the read lock
            *rguard.lock_var_mut() =
                NonZeroUsize::new(rguard.lock_var().map_or(0, |n| n.get()) + 1);
            true
        }
    }

    #[inline]
    pub unsafe fn write(&self) {
        let rguard = self.readers.lock();
        let mut wguard = self.writer.lock();
        if *wguard.lock_var() || rguard.lock_var().is_some() {
            // Another thread has the lock, wait
            drop(rguard);
            WaitQueue::wait(wguard);
            // Another thread has passed the lock to us
        } else {
            // We are just now obtaining the lock
            *wguard.lock_var_mut() = true;
        }
    }

    #[inline]
    pub unsafe fn try_write(&self) -> bool {
        let rguard = try_lock_or_false!(self.readers);
        let mut wguard = try_lock_or_false!(self.writer);
        if *wguard.lock_var() || rguard.lock_var().is_some() {
            // Another thread has the lock
            false
        } else {
            // We are just now obtaining the lock
            *wguard.lock_var_mut() = true;
            true
        }
    }

    #[inline]
    unsafe fn __read_unlock(
        &self,
        mut rguard: SpinMutexGuard<WaitVariable<Option<NonZeroUsize>>>,
        wguard: SpinMutexGuard<WaitVariable<bool>>,
    ) {
        *rguard.lock_var_mut() = NonZeroUsize::new(rguard.lock_var().unwrap().get() - 1);
        if rguard.lock_var().is_some() {
            // There are other active readers
        } else {
            if let Ok(mut wguard) = WaitQueue::notify_one(wguard) {
                // A writer was waiting, pass the lock
                *wguard.lock_var_mut() = true;
            } else {
                // No writers were waiting, the lock is released
                assert!(rguard.queue_empty());
            }
        }
    }

    #[inline]
    pub unsafe fn read_unlock(&self) {
        let rguard = self.readers.lock();
        let wguard = self.writer.lock();
        self.__read_unlock(rguard, wguard);
    }

    #[inline]
    unsafe fn __write_unlock(
        &self,
        rguard: SpinMutexGuard<WaitVariable<Option<NonZeroUsize>>>,
        wguard: SpinMutexGuard<WaitVariable<bool>>,
    ) {
        if let Err(mut wguard) = WaitQueue::notify_one(wguard) {
            // No writers waiting, release the write lock
            *wguard.lock_var_mut() = false;
            if let Ok(mut rguard) = WaitQueue::notify_all(rguard) {
                // One or more readers were waiting, pass the lock to them
                if let NotifiedTcs::All { count } = rguard.notified_tcs() {
                    *rguard.lock_var_mut() = Some(count)
                } else {
                    unreachable!() // called notify_all
                }
            } else {
                // No readers waiting, the lock is released
            }
        } else {
            // There was a thread waiting for write, just pass the lock
        }
    }

    #[inline]
    pub unsafe fn write_unlock(&self) {
        let rguard = self.readers.lock();
        let wguard = self.writer.lock();
        self.__write_unlock(rguard, wguard);
    }

    // only used by __rust_rwlock_unlock below
    #[inline]
    unsafe fn unlock(&self) {
        let rguard = self.readers.lock();
        let wguard = self.writer.lock();
        if *wguard.lock_var() == true {
            self.__write_unlock(rguard, wguard);
        } else {
            self.__read_unlock(rguard, wguard);
        }
    }

    #[inline]
    pub unsafe fn destroy(&self) {}
}

const EINVAL: i32 = 22;

// used by libunwind port
#[no_mangle]
pub unsafe extern "C" fn __rust_rwlock_rdlock(p: *mut RWLock) -> i32 {
    if p.is_null() {
        return EINVAL;
    }
    (*p).read();
    return 0;
}

#[no_mangle]
pub unsafe extern "C" fn __rust_rwlock_wrlock(p: *mut RWLock) -> i32 {
    if p.is_null() {
        return EINVAL;
    }
    (*p).write();
    return 0;
}
#[no_mangle]
pub unsafe extern "C" fn __rust_rwlock_unlock(p: *mut RWLock) -> i32 {
    if p.is_null() {
        return EINVAL;
    }
    (*p).unlock();
    return 0;
}

// the following functions are also used by the libunwind port. They're
// included here to make sure parallel codegen and LTO don't mess things up.
#[no_mangle]
pub unsafe extern "C" fn __rust_print_err(m: *mut u8, s: i32) {
    if s < 0 {
        return;
    }
    let buf = slice::from_raw_parts(m as *const u8, s as _);
    if let Ok(s) = str::from_utf8(&buf[..buf.iter().position(|&b| b == 0).unwrap_or(buf.len())]) {
        eprint!("{}", s);
    }
}

#[no_mangle]
pub unsafe extern "C" fn __rust_abort() {
    ::sys::abort_internal();
}

#[no_mangle]
pub unsafe extern "C" fn __rust_c_alloc(size: usize, align: usize) -> *mut u8 {
    alloc::alloc(Layout::from_size_align_unchecked(size, align))
}

#[no_mangle]
pub unsafe extern "C" fn __rust_c_dealloc(ptr: *mut u8, size: usize, align: usize) {
    alloc::dealloc(ptr, Layout::from_size_align_unchecked(size, align))
}

#[cfg(test)]
mod tests {

    use super::*;
    use core::array::FixedSizeArray;
    use mem::MaybeUninit;
    use {mem, ptr};

    // The below test verifies that the bytes of initialized RWLock are the ones
    // we use in libunwind.
    // If they change we need to update src/UnwindRustSgx.h in libunwind.
    #[test]
    fn test_c_rwlock_initializer() {
        const RWLOCK_INIT: &[u8] = &[
            0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
            0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
            0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
            0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
            0x3, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
            0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
            0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
            0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
            0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
            0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
            0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
            0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
            0x3, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
            0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
            0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
            0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
        ];

        let mut init = MaybeUninit::<RWLock>::zeroed();
        init.set(RWLock::new());
        assert_eq!(
            mem::transmute::<_, [u8; 128]>(init.into_inner()).as_slice(),
            RWLOCK_INIT
        );
    }
}
<|endoftext|>


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

use exonum::{
    api::{self, ServiceApiBuilder, ServiceApiState},
    blockchain::{Schema as CoreSchema, StoredConfiguration}, crypto::{CryptoHash, Hash},
    helpers::Height, node::TransactionSend, storage::StorageValue,
};

use super::{Propose, ProposeData, Schema, Vote, VoteAgainst, VotingDecision};

pub type VotesInfo = Option<Vec<Option<VotingDecision>>>;

#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub struct ConfigHashInfo {
    pub hash: Hash,
    pub config: StoredConfiguration,
    pub propose: Option<Hash>,
    pub votes: VotesInfo,
}

#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub struct ProposeHashInfo {
    pub hash: Hash,
    pub propose_data: ProposeData,
}

#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub struct ConfigInfo {
    pub committed_config: Option<StoredConfiguration>,
    pub propose: Option<ProposeData>,
}

#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub struct ProposeResponse {
    pub tx_hash: Hash,
    pub cfg_hash: Hash,
}

#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub struct VoteResponse {
    pub tx_hash: Hash,
}

#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq)]
pub struct HashQuery {
    pub hash: Hash,
}

/// Filter for stored configurations.
#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq)]
pub struct FilterQuery {
    pub previous_cfg_hash: Option<Hash>,
    pub actual_from: Option<Height>,
}

#[derive(Debug, Clone, Copy)]
pub struct PrivateApi;

#[derive(Debug, Clone, Copy)]
pub struct PublicApi;

impl FilterQuery {
    /// Checks if a supplied configuration satisfies this filter.
    fn matches(&self, cfg: &StoredConfiguration) -> bool {
        if let Some(ref prev) = self.previous_cfg_hash {
            if cfg.previous_cfg_hash != *prev {
                return false;
            }
        }

        if let Some(from_height) = self.actual_from {
            if cfg.actual_from < from_height {
                return false;
            }
        }

        true
    }
}

impl PublicApi {
    fn config_with_proofs(state: &ServiceApiState, config: StoredConfiguration) -> ConfigHashInfo {
        let propose = Schema::new(state.snapshot())
            .propose(&config.hash())
            .map(|p| p.hash());
        let votes = Self::votes_for_propose(state, &config.hash());
        ConfigHashInfo {
            hash: config.hash(),
            config,
            propose,
            votes,
        }
    }

    fn votes_for_propose(state: &ServiceApiState, config_hash: &Hash) -> VotesInfo {
        let schema = Schema::new(state.snapshot());
        if schema.propose_data_by_config_hash().contains(config_hash) {
            Some(schema.votes(config_hash))
        } else {
            None
        }
    }

    #[cfg_attr(feature = "cargo-clippy", allow(let_and_return))]
    fn proposed_configs(state: &ServiceApiState, filter: &FilterQuery) -> Vec<ProposeHashInfo> {
        let schema = Schema::new(state.snapshot());
        let index = schema.config_hash_by_ordinal();
        let proposes_by_hash = schema.propose_data_by_config_hash();

        let proposes = index
            .iter()
            .map(|cfg_hash| {
                let propose_data = proposes_by_hash.get(&cfg_hash).unwrap_or_else(|| {
                    panic!("Not found propose for following cfg_hash: {:?}", cfg_hash)
                });

                (cfg_hash, propose_data)
            })
            .filter(|&(_, ref propose_data)| {
                let cfg = <StoredConfiguration as StorageValue>::from_bytes(
                    propose_data.tx_propose().cfg().as_bytes().into(),
                );
                filter.matches(&cfg)
            })
            .map(|(hash, propose_data)| ProposeHashInfo { hash, propose_data })
            .collect();
        proposes
    }

    #[cfg_attr(feature = "cargo-clippy", allow(let_and_return))]
    fn committed_configs(state: &ServiceApiState, filter: &FilterQuery) -> Vec<ConfigHashInfo> {
        let core_schema = CoreSchema::new(state.snapshot());
        let actual_from = core_schema.configs_actual_from();
        let configs = core_schema.configs();

        let committed_configs = actual_from
            .iter()
            .map(|config_ref| {
                let config_hash = config_ref.cfg_hash();
                configs.get(config_hash).unwrap_or_else(|| {
                    panic!(
                        "Config with hash {:?} is absent in configs table",
                        config_hash
                    )
                })
            })
            .filter(|config| filter.matches(config))
            .map(|config| Self::config_with_proofs(state, config))
            .collect();
        committed_configs
    }

    fn handle_actual_config(state: &ServiceApiState, _query: ()) -> api::Result<ConfigHashInfo> {
        let config = CoreSchema::new(state.snapshot()).actual_configuration();
        Ok(Self::config_with_proofs(state, config))
    }

    fn handle_following_config(
        state: &ServiceApiState,
        _query: (),
    ) -> api::Result<Option<ConfigHashInfo>> {
        Ok(CoreSchema::new(state.snapshot())
            .following_configuration()
            .map(|cfg| Self::config_with_proofs(state, cfg)))
    }

    fn handle_config_by_hash(
        state: &ServiceApiState,
        query: HashQuery,
    ) -> api::Result<Option<ConfigInfo>> {
        let snapshot = state.snapshot();
        Ok(CoreSchema::new(&snapshot)
            .configs()
            .get(&query.hash)
            .map(|committed_config| ConfigInfo {
                committed_config: Some(committed_config),
                propose: Schema::new(&snapshot)
                    .propose_data_by_config_hash()
                    .get(&query.hash),
            }))
    }

    fn handle_votes_for_propose(
        state: &ServiceApiState,
        query: HashQuery,
    ) -> api::Result<VotesInfo> {
        Ok(Self::votes_for_propose(state, &query.hash))
    }

    fn handle_proposed_configs(
        state: &ServiceApiState,
        query: FilterQuery,
    ) -> api::Result<Vec<ProposeHashInfo>> {
        Ok(Self::proposed_configs(state, &query))
    }

    fn handle_committed_configs(
        state: &ServiceApiState,
        query: FilterQuery,
    ) -> api::Result<Vec<ConfigHashInfo>> {
        Ok(Self::committed_configs(state, &query))
    }

    pub fn wire(builder: &mut ServiceApiBuilder) {
        builder
            .public_scope()
            .endpoint("v1/configs/actual", Self::handle_actual_config)
            .endpoint("v1/configs/following", Self::handle_following_config)
            .endpoint("v1/configs", Self::handle_config_by_hash)
            .endpoint("v1/configs/votes", Self::handle_votes_for_propose)
            .endpoint("v1/configs/proposed", Self::handle_proposed_configs)
            .endpoint("v1/configs/committed", Self::handle_committed_configs);
    }
}

impl PrivateApi {
    fn handle_propose(
        state: &ServiceApiState,
        config: StoredConfiguration,
    ) -> api::Result<ProposeResponse> {
        config.consensus.warn_if_nonoptimal();

        let cfg_hash = config.hash();
        let propose = Propose::new(
            state.public_key(),
            ::std::str::from_utf8(config.into_bytes().as_slice()).unwrap(),
            state.secret_key(),
        );
        let tx_hash = propose.hash();

        state.sender().send(propose.into())?;

        Ok(ProposeResponse { tx_hash, cfg_hash })
    }

    fn handle_vote(state: &ServiceApiState, query: HashQuery) -> api::Result<VoteResponse> {
        let vote = Vote::new(state.public_key(), &query.hash, state.secret_key());
        let tx_hash = vote.hash();

        state.sender().send(vote.into())?;

        Ok(VoteResponse { tx_hash })
    }

    fn handle_vote_against(state: &ServiceApiState, query: HashQuery) -> api::Result<VoteResponse> {
        let vote_against = VoteAgainst::new(state.public_key(), &query.hash, state.secret_key());
        let tx_hash = vote_against.hash();

        state.sender().send(vote_against.into())?;

        Ok(VoteResponse { tx_hash })
    }

    pub fn wire(builder: &mut ServiceApiBuilder) {
        builder
            .private_scope()
            .endpoint_mut("v1/configs/postpropose", Self::handle_propose)
            .endpoint_mut("v1/configs/postvote", Self::handle_vote)
            .endpoint_mut("v1/configs/postagainst", Self::handle_vote_against);
    }
}
<commit_msg>Fix config info by hash (#768) [ECR-1790]<commit_after>// Copyright 2018 The Exonum Team
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//   http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

use exonum::{
    api::{self, ServiceApiBuilder, ServiceApiState},
    blockchain::{Schema as CoreSchema, StoredConfiguration}, crypto::{CryptoHash, Hash},
    helpers::Height, node::TransactionSend, storage::StorageValue,
};

use super::{Propose, ProposeData, Schema, Vote, VoteAgainst, VotingDecision};

pub type VotesInfo = Option<Vec<Option<VotingDecision>>>;

#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub struct ConfigHashInfo {
    pub hash: Hash,
    pub config: StoredConfiguration,
    pub propose: Option<Hash>,
    pub votes: VotesInfo,
}

#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub struct ProposeHashInfo {
    pub hash: Hash,
    pub propose_data: ProposeData,
}

#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub struct ConfigInfo {
    pub committed_config: Option<StoredConfiguration>,
    pub propose: Option<ProposeData>,
}

#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub struct ProposeResponse {
    pub tx_hash: Hash,
    pub cfg_hash: Hash,
}

#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub struct VoteResponse {
    pub tx_hash: Hash,
}

#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq)]
pub struct HashQuery {
    pub hash: Hash,
}

/// Filter for stored configurations.
#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq)]
pub struct FilterQuery {
    pub previous_cfg_hash: Option<Hash>,
    pub actual_from: Option<Height>,
}

#[derive(Debug, Clone, Copy)]
pub struct PrivateApi;

#[derive(Debug, Clone, Copy)]
pub struct PublicApi;

impl FilterQuery {
    /// Checks if a supplied configuration satisfies this filter.
    fn matches(&self, cfg: &StoredConfiguration) -> bool {
        if let Some(ref prev) = self.previous_cfg_hash {
            if cfg.previous_cfg_hash != *prev {
                return false;
            }
        }

        if let Some(from_height) = self.actual_from {
            if cfg.actual_from < from_height {
                return false;
            }
        }

        true
    }
}

impl PublicApi {
    fn config_with_proofs(state: &ServiceApiState, config: StoredConfiguration) -> ConfigHashInfo {
        let propose = Schema::new(state.snapshot())
            .propose(&config.hash())
            .map(|p| p.hash());
        let votes = Self::votes_for_propose(state, &config.hash());
        ConfigHashInfo {
            hash: config.hash(),
            config,
            propose,
            votes,
        }
    }

    fn votes_for_propose(state: &ServiceApiState, config_hash: &Hash) -> VotesInfo {
        let schema = Schema::new(state.snapshot());
        if schema.propose_data_by_config_hash().contains(config_hash) {
            Some(schema.votes(config_hash))
        } else {
            None
        }
    }

    #[cfg_attr(feature = "cargo-clippy", allow(let_and_return))]
    fn proposed_configs(state: &ServiceApiState, filter: &FilterQuery) -> Vec<ProposeHashInfo> {
        let schema = Schema::new(state.snapshot());
        let index = schema.config_hash_by_ordinal();
        let proposes_by_hash = schema.propose_data_by_config_hash();

        let proposes = index
            .iter()
            .map(|cfg_hash| {
                let propose_data = proposes_by_hash.get(&cfg_hash).unwrap_or_else(|| {
                    panic!("Not found propose for following cfg_hash: {:?}", cfg_hash)
                });

                (cfg_hash, propose_data)
            })
            .filter(|&(_, ref propose_data)| {
                let cfg = <StoredConfiguration as StorageValue>::from_bytes(
                    propose_data.tx_propose().cfg().as_bytes().into(),
                );
                filter.matches(&cfg)
            })
            .map(|(hash, propose_data)| ProposeHashInfo { hash, propose_data })
            .collect();
        proposes
    }

    #[cfg_attr(feature = "cargo-clippy", allow(let_and_return))]
    fn committed_configs(state: &ServiceApiState, filter: &FilterQuery) -> Vec<ConfigHashInfo> {
        let core_schema = CoreSchema::new(state.snapshot());
        let actual_from = core_schema.configs_actual_from();
        let configs = core_schema.configs();

        let committed_configs = actual_from
            .iter()
            .map(|config_ref| {
                let config_hash = config_ref.cfg_hash();
                configs.get(config_hash).unwrap_or_else(|| {
                    panic!(
                        "Config with hash {:?} is absent in configs table",
                        config_hash
                    )
                })
            })
            .filter(|config| filter.matches(config))
            .map(|config| Self::config_with_proofs(state, config))
            .collect();
        committed_configs
    }

    fn handle_actual_config(state: &ServiceApiState, _query: ()) -> api::Result<ConfigHashInfo> {
        let config = CoreSchema::new(state.snapshot()).actual_configuration();
        Ok(Self::config_with_proofs(state, config))
    }

    fn handle_following_config(
        state: &ServiceApiState,
        _query: (),
    ) -> api::Result<Option<ConfigHashInfo>> {
        Ok(CoreSchema::new(state.snapshot())
            .following_configuration()
            .map(|cfg| Self::config_with_proofs(state, cfg)))
    }

    fn handle_config_by_hash(
        state: &ServiceApiState,
        query: HashQuery,
    ) -> api::Result<ConfigInfo> {
        let snapshot = state.snapshot();

        let committed_config = CoreSchema::new(&snapshot).configs().get(&query.hash);
        let propose = Schema::new(&snapshot)
            .propose_data_by_config_hash()
            .get(&query.hash);

        Ok(ConfigInfo {
            committed_config,
            propose,
        })
    }

    fn handle_votes_for_propose(
        state: &ServiceApiState,
        query: HashQuery,
    ) -> api::Result<VotesInfo> {
        Ok(Self::votes_for_propose(state, &query.hash))
    }

    fn handle_proposed_configs(
        state: &ServiceApiState,
        query: FilterQuery,
    ) -> api::Result<Vec<ProposeHashInfo>> {
        Ok(Self::proposed_configs(state, &query))
    }

    fn handle_committed_configs(
        state: &ServiceApiState,
        query: FilterQuery,
    ) -> api::Result<Vec<ConfigHashInfo>> {
        Ok(Self::committed_configs(state, &query))
    }

    pub fn wire(builder: &mut ServiceApiBuilder) {
        builder
            .public_scope()
            .endpoint("v1/configs/actual", Self::handle_actual_config)
            .endpoint("v1/configs/following", Self::handle_following_config)
            .endpoint("v1/configs", Self::handle_config_by_hash)
            .endpoint("v1/configs/votes", Self::handle_votes_for_propose)
            .endpoint("v1/configs/proposed", Self::handle_proposed_configs)
            .endpoint("v1/configs/committed", Self::handle_committed_configs);
    }
}

impl PrivateApi {
    fn handle_propose(
        state: &ServiceApiState,
        config: StoredConfiguration,
    ) -> api::Result<ProposeResponse> {
        config.consensus.warn_if_nonoptimal();

        let cfg_hash = config.hash();
        let propose = Propose::new(
            state.public_key(),
            ::std::str::from_utf8(config.into_bytes().as_slice()).unwrap(),
            state.secret_key(),
        );
        let tx_hash = propose.hash();

        state.sender().send(propose.into())?;

        Ok(ProposeResponse { tx_hash, cfg_hash })
    }

    fn handle_vote(state: &ServiceApiState, query: HashQuery) -> api::Result<VoteResponse> {
        let vote = Vote::new(state.public_key(), &query.hash, state.secret_key());
        let tx_hash = vote.hash();

        state.sender().send(vote.into())?;

        Ok(VoteResponse { tx_hash })
    }

    fn handle_vote_against(state: &ServiceApiState, query: HashQuery) -> api::Result<VoteResponse> {
        let vote_against = VoteAgainst::new(state.public_key(), &query.hash, state.secret_key());
        let tx_hash = vote_against.hash();

        state.sender().send(vote_against.into())?;

        Ok(VoteResponse { tx_hash })
    }

    pub fn wire(builder: &mut ServiceApiBuilder) {
        builder
            .private_scope()
            .endpoint_mut("v1/configs/postpropose", Self::handle_propose)
            .endpoint_mut("v1/configs/postvote", Self::handle_vote)
            .endpoint_mut("v1/configs/postagainst", Self::handle_vote_against);
    }
}
<|endoftext|>